01.Dart开发环境安装
概述
- Dart可以用来开发移动应用、Web应用、开发命令行应用和服务端应用,主要有一下IDE可以选择
-
VS Code 在VS Code中安装Dart插件来开发
-
Android Studio Android Studio主要用来进行移动应用开发
- WebStorm, IntelliJ, DartPad在线运行(但无法引用三方库)
- Dart SDK包含开发Web,命令行和服务端应用所需要的库和命令行工具。如果你只是想要开发移动应用,则不需要使用Dart SDK,只需安装 Flutter即可。
brew tap dart-lang/dart
brew install dart
brew upgrade dart
dart --version //dart
Dart VM version: 2.7.1 (Thu Jan 23 13:02:26 2020 +0100) on "macos_x64"
-> vim .bash_profile
-> export PATH=${PATH}:/usr/local/Cellar/dart/2.7.1/bin
-> source .bash_profile
02.Dart基本概念
重要概念
-
一切皆对象:所有变量引用的都是对象,数字、函数、null都是对象,都继承自Object类。
-
Dart 声明变量类型可选:Dart可以进行类型推断,dynamic可以声明一个不确定的类型(与进行类型推断的var不同)。
-
Dart支持泛型:List<int>或List<dynamic>(由任何类型对象组成的列表)
-
Dart支持顶级函数,支持属于类或对象的函数,支持嵌套函数:main
- Dart支持顶级变量,支持属于类或对象的变量
-
标识符下划线开头表示库内私有:_number, _name()
- 标识符由字母、数字、下划线组成,由字母或下划线开头
- Dart表达式有值,语句没有值
- Dart工具可以显示警告和错误两个类型
关键字
abstract2
|
dynamic2
|
implements2
|
show1
|
as2 |
else |
import2 |
static2 |
assert |
enum |
in |
super |
async1 |
export2 |
interface2 |
switch |
await3 |
extends |
is |
sync1 |
break |
external2 |
library2 |
this |
case |
factory2 |
mixin2 |
throw |
catch |
false |
new |
true |
class |
final |
null |
try |
const |
finally |
on1 |
typedef2 |
continue |
for |
operator2 |
var |
covariant2 |
Function2 |
part2 |
void |
default |
get2 |
rethrow |
while |
deferred2 |
hide1 |
return |
with |
do |
if |
set2 |
yield3 |
注:
1. 上下文关键字,只有在特定的场景才有意义
2. 内置标识符,javascript代码转为dart代码更简单
3. dart1.0之后发布的、支持异步的相关标识符
关键字
- 变量仅存储对象的引用(说明变量也是个对象)
- 变量声明的时候可以不指定类型
- 未初始化的变量内容都为null(int未初始化也是null)
- 可以使用关键字final或者const修饰变量,final只能赋值一次,const为编译时常量,顶层的final变量或者类的final变量在其第一次使用的时候被初始化
03.Dart内置类型
int
- 长度不超过64位(8字节),具体取值范围依赖于不同的平台。在DartVM上其取值位于-263至263-1之间。编译成JavaScript的Dart使用JavaScript数字,其允许的取值范围在-253至253-1之间
- 思考:Dart中的int 与 Java中的int和long 如何对应?
double
- 64位的双精度浮点数字
- 思考:Dart中的double 与 Java中的double和float 如何对应?
String
- Dart字符串是UTF-16编码的字符序列。可以使用单引号或者双引号来创建字符串。(无区别)
- 可以使用 + 运算符将两个字符串连接为一个,也可以将多个字符串挨着放在一起 连接为一个
- 使用三个单引号或者三个双引号创建多行字符串
- 字符串前加上 r 作为前缀,创建“raw”字符串(不会被做任何处理)
- ==运算符判断两个对象内容是否一样
Booleans
- bool关键字表示布尔类型,布尔类型只有两个对象true和false,编译时常量
- Dart的类型安全不允许使用类似if(nonbooleanValue)的代码去检查布尔值(if(1),其他语言中非0既是true不成立)
List
- Dart中数组由List对象表示
- 下标从0开始
- List list = List(); //固定长度为数组,无参为可变长度
- Dart在2.3引入了扩展操作符(...)和null-aware扩展操作符(...?),他们提供了一种将多个元素插入集合的简洁方法,还引入了collection if 和collection for
-
List list_1 = new List(); //list
List list_2 = List(5); //array
var list = [1, 2, 3];
var list1 = [0, ...list]; //[0, 1, 2, 3];
var list2 = [0, ...?list]; //如果list不为空就赋值
const list3 = [0, 1, 2];
list3[1] = 3; //运行会报错,const的列表不能更改
var list4 = [0, 1, 2, if(2<3)3];//[0, 1, 2, 3]; collection if
var list5 = [1, 2, 3];
var list6 = ["0", for(var i in list5) '$i']; //[0, 1, 2, 3]; collection for
Sets
- Dart中使用Set类表示无序且元素唯一的集合
- 支持Set字面量(Dart2.2加入)以及Set类型两种形式的Set
var set1 = {'a'}; //set
var set2 = {}; //!!!不是set
var set3 = <int>{}; //是空set,或者var set3 = <dynamic>{};
//因为set在dart2.2才加入,之前{}表示map
Set<int> set4 = Set(); //建议标明泛型
set4.add(123);
set4.add(123);//再次add,只有唯一元素
const set5 = {'a'}; //不能再修改
Maps
- Dart中Map通过Map字面量和Map类型来实现
- 每个键只能出现一次,但是值的出现没有限制
var map1 = {0:"a", 1:"b"};
Map map2 = Map();
map2[0] = "a";
Map<int, String> map3 = new Map();
map3[0]; //0是key,不是下标,此时为null
map3[0] = "a"; //再取为a
final map4 = const{0:"a", 1:"b"};
map4[1]="aaa"; //运行会报错,不可改变
Runes
- Dart使用Runes来表示UTF-32编码的字符串
- String类中codeUnitAt和codeUnit属性返回16位代码单元,runes属性可以获取字符串的Runes
Symbols
- Symbol表示Dart中声明的操作符或者标识符,改类型的对象几乎不会被使用到
- 可以使用在标识符前加 # 前缀来获取Symbol
- Symbol字面量是编译时常量
04.Dart方法
Dart是一种真正面向对象的语言,所以函数也是对象并且类型为Function,这意味着函数可以被复制给变量或者作为其他函数的参数。你也可以像调用函数一样调用Dart类的实例。
参数
- 函数可以有两种形式的参数:必要参数和可选参数
- 必要参数定义在参数列表的前面
- 可选参数则定义在必要参数的后面
可选参数
- 可选参数分为命名参数和位置参数
- 可在命名参数和位置参数中任选其一使用,但是不能混用
命名参数:
1.使用参数名:参数值 的形式来指定命名参数
2.用大括号来指定命名参数
3.可以提供默认值
4.@required注解来标识一个命名参数是必须的参数
int add(int a, int b, {int c, int d, int e}){
return a + b;
}
int add({@required int a, @required int b, int c, int d, int e}){ //需要引入包
return a + b;
}
void main{
int c = add(2, 3);
int d = add(2, 3, c:4, e:5);
}
位置参数:
1.使用[]将一些列参数包裹起来作为位置参数
2.可以用 = 为函数的位置参数定义默认值,默认值必须为编译时常量,没有指定默认值的情况下默认值为null
int add(int a, [int b, int c]){
return a + (b??0) + (c??0);
}
void addValue(int a, [int b=0, int c=0]){
return a + b + c;
}
void main{
int a = add(1);
int b = add(1, 2);
int c = add(1, 2, 3);
}
main函数
每个Dart程序都必须有一个main()顶级函数作为程序的入口,main()函数返回值为void并且有一个List<String>类型的可选参数
函数作为一级对象
- 可以将函数作为参数传递给另一个函数
- 可以将函数赋值给一个变量
void printE(int e){
print(e);
}
void main(){
//源码
//void forEach(){
// for (E element in this) f(element);
//}
var list = [1, 2, 3];
var f = printE;
list.forEach(f);
list.forEach(printE); //void f(E e){}
//相同作用
for(var v in list){
printE(v);
}
var a = (e) => "xxx $e"; //胖箭头语法
var b = (String e) => "xxx $e";
//相同作用
var c = (e){
return "xxx $e";
}
var d = (String e){
return "xxx $e";
}
a("mmm");//返回 xxx mmm
}
匿名函数
- 没有名字的函数就是匿名函数
- 称之为匿名函数,嚯Lambda表达式嚯Closure闭包
([[类型] 参数[, ...]]){
函数体
}
词法作用域
- 变量的作用域在写代码的时候就确定了
- 大括号内定义的变量只能在大括号内使用(与java类似)
词法闭包
- 闭包 即一个函数对象,即使函数对象的调用在它原始作用域之外,依然能够访问在它词法作用域内的变量
Function addValue(int baseValue){ //Function可以省略
return (int j) => baseValue + j; //返回一个词法闭包
}
void main(){
var add1 = addValue(5);
print(add1); //打印 Closure:(int) => int ,说明返回的add1是一个闭包
print(add1(4)); //打印 9,说明5虽然在原始作用域之外了,但是依然能访问
}
函数是否相等
void foo(){} //定义顶层函数
class A {
static void bar(){} //定义静态方法
void baz(){} //定义实例方法
}
void main(){
var x;
//比较顶层函数是否相等 == 相等
x = foo;
assert(foo == x);
//比较静态方法是否相等 == 相等
x = A.bar;
assert(A.bar == x);
//比较实例方法是否相等:
var a1 = A(); //A的实例 a1
var a2 = A(); //A的实例 a2
var y = a2;
x = a2.baz;
//这两个闭包引用了相同的实例对象,因此他们相等
assert(y.baz == x);
//这两个闭包引用了不同的实例对象,因此他们不相等
assert(a1.baz != a2.baz);
}
返回值
- 所有函数都有返回值
- 没有显示返回语句的函数最后一行默认执行return null
05.Dart运算符
运算符列表
描述 |
运算符 |
一元后缀 |
表达式++ 表达式-- () [] . ?. |
一元前缀 |
-表达式 !表达式 ~表达式 ++表达式 --表达式 |
乘除法 |
* / % ~/ |
加减法 |
+ - |
位运算 |
<< >> >>> |
二进制与 |
& |
二进制异或 |
^ |
二进制或 |
I |
关系和类型测试 |
>= > <= < as is is! |
相等判断 |
== != |
逻辑与 |
&& |
逻辑或 |
II |
空判断 |
?? |
条件表达式 |
表达式1 ? 表达式2 : 表达式3 |
级联 |
.. |
赋值 |
= *= /= += -= &= ^= 等等 |
优先级:从上到下,从左到右
算数运算符
运算符 |
描述 |
+ |
加 |
- |
减 |
-表达式 |
一元负,也可以作为反转(反转表达式的符号) |
* |
乘 |
/ |
除 |
~/ |
除并取整 |
% |
取模 |
++var |
var = var+1(表达式值为var+1) |
var++ |
var = var+1(表达式值为var) |
--var |
var = var-1(表达式值为var-1) |
var-- |
var = var-1(表达式值为var) |
void main(){
int a=3, b=2;
var f = a/b; //得1.5(double) ,在java和c中为取整的1
print(f);
var g = a~/b; //得1,这是dart中的除整
print(g);
}
算数运算符
运算符 |
描述 |
== |
相等 |
!= |
不等 |
> |
大于 |
< |
小于 |
>= |
大于等于 |
<= |
小于等于 |
类型判断运算符
运算符 |
描述 |
as |
类型转换(也用作指定类前缀) |
is |
如果对象是指定类型则返回true |
is! |
如果对象是指定类型则返回false |
class A{
}
class B extends A{
}
void main(){
A aa = A();
aa is A; //true
B bb = B();
bb is A; //true
bb as A; //把bb转换为特定类型,要内部会先进行is判断
}
赋值运算符
- 使用 = 来赋值
- 使用 ??= 来为值为null的变量赋值
= |
-= |
/= |
%= |
>>= |
^= |
+= |
*= |
~/= |
<<= |
&= |
I= |
var a = 1;
var b ;
a ??= 2;
b ??= 4;
print(a); //打印1 a已赋值, ??=不再为它赋值
print(b); //打印4 b未赋值,??=将它赋值为4
逻辑运算符
运算符 |
描述 |
! !表达式 |
对表达式结果取反 |
II |
逻辑或 |
&& |
逻辑与 |
按位和移位运算符(仅适用于整数)
运算符 |
描述 |
& |
按位与 |
I |
按位或 |
^ |
按位异或 |
~表达式 |
按位取反 |
<< |
位左移 |
>> |
位右移 |
条件表达式
condition ? expr1 : expr2 //同java三目运算符
expr1 ?? expr2 //如果表达式1为非null,则返回其值,否则执行表达式2 并返回其值
级联运算符
- 级联运算(...)可以让你在同一个对象上连续调用多个对象的变量或方法
class B{
int a = 4;
int b = 5;
}
class A{
int a = 0;
double b = 1/0;
String c = "c";
B temp;
}
void main(){
A aa = A();
aa.a = 2;
aa.b = 2.0;
aa.c = "asd";
//级联写法
A bb = A();
bb..a = 2
..b = 1.2
..c = "zzz"
..temp = B()..a = 3..b = 2;
}
其他运算符
运算符 |
名字 |
描述 |
() |
使用方法 |
代表调用一个方法 |
[] |
访问List |
访问List中特定位置的元素 |
. |
访问成员 |
成员访问符 |
?. |
条件访问成员 |
与上述成员访问符类似,但是左边的操作对象不能为null, 例如 foo?.bar,如果foo为null则返回null,否则返回bar |