重要概念
- 所有能够使用变量引用的都是对象,每个对象都是一个类的实例。在Dart中甚至连数字、方法和null都是对象。所有的对象都继承于Object类。
- 使用静态类型可以更清晰的表明你的意图,并且可以让静态分析工具来分析你的代码,但这并不是牵制性的。(在调试代码的时候你可能注意到 没有指定类型的变量的类型为dynamic。)
- Dart在运行之前会先解析你的代码。你可以通过使用类型或者编译时常量来帮助Dart去捕获异常以及让代码运行的更高效。
- Dar支持顶级方法(例如 main()),同时还支持在类中定义函数。(静态函数和实例函数)。你还可以在方法中定义方法(嵌套方法或者局部方法)。
- 同样,Dart还支持顶级变量,以及在类中定义变量(静态变量和实例变量)。实例变量有时候被称之为域(Fields)或者属性(Properties)。
- 和Java不同的是,Dart 没有public、 protected、 和private关键字。如果一个标识符以(_)开头,则该标识符在库内是私有的。
- 标识符可以以字母或者 _ 下划线开头,后面可以是其他字符和数字的组合。
- 有时候表达式expression和语句 statement 是有区别的,所以这种情况我们会分别指明每种情况。
- Dart工具可以指出两种问题:警告和错误。警告只是说你的代码可能有问题,但是并不会阻止你的代码执行。错误可以是编译时错误也可以是运行时错误。遇到编译时错误时,代码将无法执行;运行时错误将会在运行代码的时候导致一个异常。
Dart语法
变量
- Dart中变量初始值为null,即使是int类型也可以是null(java中int默认是0, boolean默认是false);
- Dart支持自识别,可以是用var定义变量,也可以直接指定具体类型;
- final或者const都可修饰不可变的变量,final变量只能赋值一次,const是编译时常量。
// 指定具体类型
bool x = true;
int y = 2;
double z = 2.13;
// 用var定义变量,不用指定具体类型
var a = true;
var b = 2;
var c = 2.13;
final name = 'Tom';
const num = 200000;
基本类型
- int和double是num子类,没有float类型;
- 支持字符串模板,用${expression}的方式来实现字符串效果,类似如字符串拼接;
- String可以使用单引号或者双引号;
- Dart没有数组,只有列表;
- 其中List,Set,Map不是抽象接口,是具体实现类,可直接使用;
- Map的key没有指定类型,key类型不一致不会报错;key不能相同,但是value可以相同,value可以为null。
var name = 'Tom';
// 使用$来实现name参数传入
var student = 'name is:$name';
// 使用构造函数创建List对象,和java一样
var list = List<int>();
list.add(1);
// 创建不可变List
var list1 = const[1,2];
// for-in循环,这里用到Dart中的in关键字
var list2 = [1,2,3,4];
for (var i in list2) {
print(i);
}
void main() {
// 通过构造器创建Map
Map map = new Map();
map['a'] = 'Android';
map['b'] = 'Flutter';
map['c'] = 'IOS';
print(map);
// 通过复制的方式
Map map1 = Map.of(map);
print(map1);
// 直接声明来创建Map
Map map2 = {'a': 'Android', 'b': 'Flutter', 'c': 'IOS'};
print(map2);
}
方法
- 方法也是对象,方法可赋值给一个变量;
- 如果方法的参数是解构出来的可以通过 @required 注解标注为必填 const Scrollbar({Key key, @required Widget child});
- 支持可选参数,可选命名参数用{}包围,可选位置参数写在最后并且使用[]包围 String say(String from, String msg, [String device]);
- 支持默认参数 void enableFlags({bool bold = false, bool hidden = false}) {…};
- 以_开头的方法都是私有的。
void main() {
// 方法赋值给myarea对象
var myarea = _area(2,3);
print(myarea);
print(area2(2));
print(area3(2, height: 1, judge: false));
}
num _area(num width, num height) {
return width * height;
}
// 使用@required来标注必须参数
num area1({@required num width, @required num height}) {
return width * height;
}
// 可选参数
num area2(num width, [num height]) {
if (height != null) {
return width * height;
}
return 0;
}
// 默认参数
num area3(num width, {num height = 1, bool judge = true}){
if (judge) {
return width * height;
}
return 0;
闭包
支持闭包,闭包能够访问外部方法内部的局部变量
void main() {
var foo = a();
foo ();
foo ();
foo ();
foo ();
}
// 定义闭包
a() {
int count = 0;
// 匿名函数
return (){
print(count++);
};
}
嵌套函数
// 外层函数
void showName(var name) {
// 函数中嵌套函数
void printName(var name) {
print("Hello name is: $name");
}
// 使嵌套函数生效
printName(name);
}
// 主函数调用
void main() {
showName("Tom");
}
操作符
1.空替换?? expr1 ?? expr2,如果expr1是non-null,返回其值。否则执行expr2并返回其结果;
2.条件成员访问?.P?.y = 4; 如果p是non-null,则设置y的值等于4;
3.类型判定操作符(as,is,is!);
4.级联操作,可以在同一个对象上连续调用多个函数以及访问成员变量;
// 条件操作符(特有的 ??)
var oldState ;
// 传统的写法
var newState = (oldState == null) ? oldState : 'not final';
// 使用??操作符
var newState1 = oldState ?? 'not final';
// 避空(特有的?.)
void main() {
Person person = new Person('Tom');
Person person1 = null ;
// person 非空,正常返回
print(person?.name);
// person1为空,正常返回null
print(person1?.name);
// peroson1为空,报异常
print(person1.name);
}
class Person {
final String name;
Person(this.name);
}
// 类型判定操作符(as,is,is!,):
void main() {
var person = new Person();
// 判断person是不是Person类型
if (person is! Person) {
print("person is not Person type");
}
if (person is Person) {
person.name = 'Tom';
print(person.name);
}
// 上面代码可以使用as简化,as是把操作符对象转化为特定的类型
(person as Person).name = 'Tom';
print(person.name);
// 上面两种写法有区别,第一种是如果是true就执行里面的内容,false就不执行;
// 第二种情况使用as会抛出一个异常
}
class Person {
var name;
}
// 级联操作
// 获取一个id为btn1的按钮对象
var btn = query('#btn1');
btn.text = '确定';
btn.classes.add('ButtonStyle');
btn.onClick.listen((s) => window.alert('ok'));
// 上面代码等价于
query('#btn1')
..text = '确定'
..classes.add('ButtonStyle')
..onClisk.listen((s) => window.alert('ok'));
异常
- 和java不同的是,Dart可以抛出任意类型的对象;
- 程序不会强制要求开发中处理异常,但若发生异常,程序会中断;
- 其中异常主要分为Error和Exception两种类型。
void main() {
try {
test();
} on RangeError catch (e) {
print(e);
} on Error catch (e) {
print(e);
} finally {
print('finally');
}
}
test() {
throw RangeError("下标越界");
}
类
- 创建对象可以不使用new关键字;
- Dart中没有public,private,protected这些关键字;
- 没有interfaces关键字,每一个类都是一个接口。我们可以用抽象类来类比java中的接口;
- Dart把多重继承的类叫做Mixins。
main() {
var point = new Point();
point.run();
// 这里会执行P类中的run()
// 可以理解成优先级覆盖,子类>重用>父类
P p = new P();
p.run();
Q q = new Q();
q.run();
}
class Point {
void run() {
print("Point run...");
}
}
class Note {
void run() {
print("Note run...");
}
}
// 多继承
class P extends Point with Note {
void run() {
print("P run...");
}
}
class Q implements Point {
@override
void run() {
print("Q run...");
}
}
构造函数
- 支持语法糖 Point(this.x, this.y);
- 每个实例变量都会自动生成一个getter方法,Non-final变量还会自动生成一个setter;
- 命名构造函数,使用命名构造函数可以为一个类实现多个构造函数,也能更加清晰的表明你的意图;
- 构造函数不能被继承,如果子类没有自定义的构造函数,会有一个默认的构造函数。
void main() {
var person = new Person("张三", 18, "Wuhan");
var person1 = new Person.init("李四", 20, "Shanghai");
// setter
person.name = "张三丰";
// getter
print(person.name);
print(person);
print(person1);
}
class Person {
var name;
int age;
final String address;
@override
String toString() {
return "name:$name age:$age address:$address";
}
Person(name, age, this.address) {
this.name = name;
this.age = age;
print("这里是传统的构造函数");
}
// 语法糖形式,命名构造函数
Person(this.name, this.age, this.address){
print("这里是语法糖的构造函数");
}
Person.init(this.name, this.age, this.address) {
print("这里是命名构造函数");
}
断言
- 断言是如果条件表达式不满足则停止代码执行;
- 断言只在检查模式下运行有效,如果在生产模式下运行则不会执行。
// 确保变量是非空值
assert(text != null);
// 确保值是小于100
assert(number < 100);
// 确保这是一个 https 地址
assert(urlString.startsWith('https'));
注:检查模式是进行类型检查,如果发现实际类型和声明或期望类型不匹配就报错;生产模式是不进行类型检查,忽略声明的类型信息,比如可以忽略assert语句。Dart默认是生产模式。
参考:
[Dart语法预览](http://dart.goodev.org/guides/language/language-tour)