Dart语法
1、变量类型
var/const/final 变量名称 = 值
1.1、var
var实际上是编译期抛给我们的“语法糖”,一旦被编译,编译期会自动匹配var 变量的实际类型,并用实际类型来替换该变量的申明,就像我们在编码时候用实际类型进行申明,可被同类型赋值。
var age = 18;
age = 20;
age = "20"; // 错误
1.2、const与final(常用)
?const: 编译期 + 常量。
赋值时,内容必须在编译期间就得确定下来。
const必须初始化,只能赋值一次且不能修改值,赋值必须是常量。
使用const关键字声明的变量是隐式final的。
可以把const 常量赋给 final 变量,反过来不可以。
const对象无法访问运行时需要计算的任何内容。
?final: 运行期 + 常量 + 变量。
赋值时,可以动态获取,比如通过一个函数来赋值。final必须初始化声明,只能赋值一次且不能修改值,赋值可以是常量也可以是变量。
?final和const可以与变量的数据类型一起使用,也可以与 var 关键字一起使用。
String getName(){ return "hello"; }
const name = getName(); // 错误
const放在赋值语句右边(等号右边),可贡献对象,提高性能。
class Person { const Person(); }
final a = const Person();
final b = const Person();
print(identical(a,b)); // true 比较类型一致
final c = const Person();
final d = const Person();
print(identical(c,d)); // false 类型不一致
2、数据类型
2.1、数字类型
int age = 11;
int hexAge = 0x12;
double height = 1.88;
?字符串和数字之间得转化
1、字符串转数字(int和double)
var a = int.parse(’111‘);
var b = double.parse('1.99');
print('${a} ${one.runtimeType}');
print('$a $one.runtimeType');
2、数字转字符串
var num1 = 123;
var num2 = 123.456;
var numStr1 = num1.toString();
var numStr2 = num2.toString();
var numStr3 = num2.toStringAsFixed(2); // 保留两位小数
2.2、布尔类型
注:dart中不能判断非0即真,非空即真,明确定义true和false;
var isFlag = true;
if(isFlag){} // 正确
if(!0){} // 错误
2.3、字符串类型
?单行字符串
var s1 = "Hello World";
var s2 = ‘Hello World’;
?多行字符串
var s2 = '"
哈哈哈
呵呵呵
"'
?拼接字符串
var name = ’name‘;
var age = 18;
var height = 1.88;
var isBoy = false;
print('my name is ${name}, age is $age, height is $height, I am is $isBoy');
注:字符串和其他变量或表达式拼接: 使用${expression}, 如果表达式是一种标识符, 那么{}可以省略。
3、集合类型
3.1、List [ .x.x. ]
类型推导:var letters = ['a','b','b','c'];
明确指定类型:List<int> letters = [1,2,2,3,4];
3.2、Set { .x.x. }
Set是无序且不重复。
var lettersSet = {'a','b','c','d'};
Set<int> lettersSet = {1,3,2,4,5};
3.3、Map { x:x ,x :x }
var infoMap1 = {'name':'zhangsan' , 'age':"18"};
Map<String,Object> infoMap2 = {'name': 'lisi', 'age': 18};
3.4、集合的常见操作
?长度
letters.length
lettersSet.length
infoMap1.length
?增删改
letters.add('e');
lettersSet.add('e');
letters.remove('a'); // 删除内容 可能存在多个
lettersSet.remove('a'); // 删除一个内容
letters.contains('a');
lettersSet.contains('a');
?List元素有序,删除指定索引位置元素
letters.removeAt(3);
print('$letters');
3.5、Map的常见操作
?获取某个value
print(infoMap1['name']);
结果:张三
?获取所有entries(键值对)
print('${infoMap1.entries} ${infoMap1.entries.runtimeType}');
结果:(MapEntry(name:why),MapEntry(age:18))
?获取所有keys
print('${infoMap1.keys}')
结果:(name,age)
?获取所有values
print('${infoMap1.values}')
结果:(zhangsan,18)
?判断是否包含某个key或value
print('${infoMap1.contains('name')}')
结果:true
?根据key删除元素
infoMap1.remove('age');
4、函数
4.1、函数参数
?可选函数
命名可选参数:{param1,param2,...}
printInfo(String name, {int age, double height}) { ... }
printInfo('lisi');
printInfo('lisi', age:18);
printInfo('lisi', height:1.80);
printInfo('lisi', age:18, height:1.80);
loadData(String key, {int pageIndex=1, int pageSize=10}){
....
}
loadData("厦门",pageIndex:2)
注:对于可选参数中,可通过声明@required指定为必传项。
位置可选参数:[param1,param2,...]
可选位置参数是位置,如果想指定某个位置上的参数值,则必须前面位置的已经有值,即使前面的值存在默认值也不行。
void buildHouse(String name, [String where, int range]){ ... }
void buildHouseDefault(String name, [String where = 'shanghai',int range]);
buildHouse('zhangsan', 10); // 错误
buildHouse('zhangsan', 'shanghai', 10); // 正确
buildHouseDefault('lisi', 10); // 错误
buikldHouseDefault('lisi', 'beijing', 10); // 正确
注:对于可选参数中,可通过声明@required指定为必传项。
可选参数可指定默认值
printInfo(String name, {int age 18, double height=1.70}){ ... }
printInfo('zhangsan',20);
结果:zhangsan,20,1.70(默认值而非null)
4.2、函数是一等公民
java/oc不能将函数作为一等公民适用,不够灵活。现在语言基本都支持函数作为一等公民适用,dart也支持。
将函数赋值给一个变量, 也可以将函数作为另外一个函数的参数或者返回值来使用。
首先,定义一个函数
foo(String name) { print('传入的name:$name'); }
?将函数作为另一个函数的参数
text(Function func) {
func('coderwhy');
}
?将函数作为另一个函数的返回值
getFunc() {
return foo;
}
?将函数赋值给一个变量
var bar = foo;
?将函数作为另一个函数的参数
test(foo);
?将函数作为另一个函数的返回值
var func = getFunc();
4.3、匿名函数
某些情况下,给函数命名太麻烦了,我们可以使用没有名字的函数,这种函数可以被称之为匿名函数( anonymous function),也可以叫lambda或者closure。
var moives = ['盗梦空间', '星际穿越', '少年派', '大话西游'];
moives.forEach( (element) { print('element'); } );
moives.forEach( (item) => print(item) );
func1((Object o) {
})
4.4、词法作用域
dart词法有自己明确作用域范围,它是根据代码结构({})来决定作用域范围的优先使用自己作用域中的变量,如果没找到,则一层层向外查找。
4.5、词法闭包
闭包可以访问其词法范围内的变量,即使函数在其它地方被使用,也可以正常访问。
4.6、返回值问题
所有函数都返回一个值,如果没指定返回值,则语句返回null,隐式附加到函数体。
5、运算符
5.1、除法/、整除~/、取模%运算
var num = 7;
print(num / 3); // 除法,结果:2.333
print(num ~/ 3); // 整除,结果:2
print(num % 3); // 取模,结果:1
5.2、赋值操作 ??=
Dart有一个很多语言都不具备的赋值运算符:
●当变量为null时,使用后面的内容进行赋值。
●当变量有值时,使用自己原来的值。
var name2 = 'kobe';
// var name2 = null;
name2 ??= 'james';
print(name2);
// 当name2初始化为kobe时,结果为kobe
// 当name2初始化为null时,结果为james
java: 条件 ?true : false
5.3、条件运算符 ??
Dart中包含一直比较特殊的条件运算符:expr1 ?? expr2
●如果expr1是null,则返回expr2的结果;
●如果expr1不是null,直接使用expr1的结果。
●类似java中三目运算符
var temp = 'kobe';
var temp = null;
var name = temp ?? 'kobe';
print(name);
5.4、级联语法 ..
某些时候,我们希望对一个对象进行连续的操作,这个时候可以使用级联语法。
class Person() {
String name;
void run() {
print('${name} is running');
}
void eat() {
print('${name} is eating');
}
}
main(List<String> args) {
final p1 = Person();
p1.name = 'lisi';
p1.run();
p1.eat();
final p2 = Person()
..name = 'zhangsan'
..run()
..eat();
}
6、流程控制
6.1、if和else
注意:不支持非空即真或者非0即真,必须有明确的bool类型。
6.2、循环操作
var names = ['a','b','c'];
for(var i = 0, i < names.length, i++) { ... }
for(var item in names) { ... }
names.forEach(item => { print(item); })
while和do-while和其它语言一致。
break和continue用于也一致。
6.3、switch-case
注:每个case语句,默认情况必须以break结尾。
var direction = 'east';
switch(direction) {
case 'east':
break;
case 'south':
break;
default:
break;
}
7、类和对象
7.1、类的定义
注:类方法中可省略this,但有命名冲突时,this不能省略。
Main() {
var p1 = Person(); // dart2开始可省略new
var map = Map();
p1.name = ‘why’;
p1.eat();
Var p2 = Person(‘aaa’);
}
Class Person {
String name;
Int age;
Java 构造函数:
Person(){}
Person(String name){}
Person( Int age){}
Person( String name,Int age){}
// 可选参数(灵活性)
Person({String mName, int mAge}){
name = mName;
age = mAge;
}
eat() {
print(‘$name 在吃东西’);
}
}
7.2、构造方法
1、普通构造方法
有了自己的构造方法,默认的构造方法失效。
Dart不支持函数的重载(名称相同,参数不同的方式),假如写了默认构造方法,会和我们自定义构造方法冲突。
上面的构造方法可优化为下面的写法:
Person(this.name,this.age);
2、命名构造方法
在开发中, 我们确实希望实现更多的构造方法,怎么办呢?
因为不支持方法(函数)的重载,所以我们没办法创建相同名称的构造方法。我们需要使用命名构造方法:
利用命名构造方法,提供更加便捷的创建对象方式:
开发中,我们需要经常将一个Map转成对象,可以提供如下的构造方法:
1、初始化列表
我们来重新定义一个类Point, 传入x/y,可以得到它们的距离distance:
2、重定向构造方法
在某些情况下, 我们希望在一个构造方法中去调用另外一个构造方法, 这个时候可以使用重定向构造方法:
3、常量构造方法
某些情况下,传入相同值时,我们希望返回同一个对象,这个时候,可以使用常量构造方法。
默认情况,创建对象时,即使传入相同的参数,创建出来的也不是同一个对象:
如果将构造方法前加const进行修饰,那么可以保证同一个参数,创建出来的对象是相同的:
常量构造方法有一些注意点:
注意一:拥有常量构造方法的类中,所有的成员变量必须是final修饰的。
注意二: 为了可以通过常量构造方法,创建出相同的对象,不再使用 new关键字,而是使用const关键字。
如果是将结果赋值给const修饰的标识符时,const可以省略。
4、工厂构造方法
Dart提供了factory关键字, 用于通过工厂去获取对象。
7.3、setter和getter
默认情况下,Dart中类定义的属性是可以直接被外界访问的。
某些情况,我们希望监控这个类的属性被访问的过程,这个时候就可以使用setter和getter了。
7.4、类的继承
7.5、抽象类
什么是 抽象方法?
在Dart中没有具体实现的方法(没有方法体),就是抽象方法。
抽象方法,必须存在于抽象类中。
抽象类是使用abstract声明的类。
注意:
1、抽象类不能实例化。
2、抽象类中抽象方法必须被子类实现,抽象类中的已经被实现方法可以不被子类重写。
abstract class Person {
getA(); // 子类必须实现
String getStr() { // 子类可选择性重写
Return “hello Str”;
}
}
7.6、隐式接口
Dart中的接口比较特殊, 没有一个专门的关键字来声明接口.
Dart不支持多继承,默认情况下,定义的每个类都相当于默认也声明了一个接口,可由其它类来实现。
开发中,将用于给别人实现的类声明为抽象类:
7.7、Mimin混入
在java中通过implements实现某个类时,类中所有的方法都必须被重新实现(无论这个类原来是否已经实现过该方法)。
某些情况下,一个类可能希望直接复用之前类的原有实现方案,怎么做呢?
l 使用继承吗?但是Dart只支持单继承,那么意味着你只能复用一个类的实现。
Dart提供了另外一种方案: Mixin混入的方式
l 除了可以通过class定义类之外,也可以通过mixin关键字来定义一个类。
l 只是通过mixin定义的类用于被其他类混入使用,通过with关键字来进行混入。
7.8、类成员和方法
在类中定义的成员和方法都属于对象级别的。
在开发中, 我们有时候也需要定义类级别的成员和方法。
Dart中,使用static关键字定义,类静态调用。
7.9、枚举类型
枚举在开发中也非常常见, 枚举也是一种特殊的类, 通常用于表示固定数量的常量值。
1、枚举的定义
2、枚举的属性
枚举类型中有两个比较常见的属性:
l index: 用于表示每个枚举常量的索引, 从0开始。
l values: 包含每个枚举值的List。
枚举类型的注意事项:
注意一: 您不能子类化、混合或实现枚举。
注意二: 不能显式实例化一个枚举。
如果对您有帮助,帮忙关注下,您的关注是我更新最大的动力!谢谢~~
本文暂时没有评论,来添加一个吧(●'◡'●)