Dart语法学习
目录
- 参考资料
- 语言特性
- 关键字
- 变量与常量
- 数据类型
- 运算符 operators
- 控制流程语句
- 异常 Exceptions
- 函数 Function
- 类 Class
- 类-方法
- 类-抽象类
- 类-隐式接口
- 类-扩展一个类(重写)
- 库和可见性
- 异步支持
参考资料
语言特性
-
Dart所有的东西都是对象, 即使是数字numbers、函数function、null也都是对象,所有的对象都继承自Object类。
-
Dart动态类型语言, 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)。
-
Dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度。
-
Dart中的类和接口是统一的,类即接口,你可以继承一个类,也可以实现一个类(接口),自然也包含了良好的面向对象和并发编程的支持。
-
Dart 提供了顶级函数(如:main())。
-
Dart 没有 public、private、protected 这些关键字,变量名以"_"开头意味着对它的 lib 是私有的。
-
没有初始化的变量都会被赋予默认值 null。
-
final的值只能被设定一次。const 是一个编译时的常量,可以通过 const 来创建常量值,var c=const[];,这里 c 还是一个变量,只是被赋值了一个常量值,它还是可以赋其它值。实例变量可以是 final,但不能是 const。
-
编程语言并不是孤立存在的,Dart也是这样,他由语言规范、虚拟机、类库和工具等组成:
- SDK:SDK 包含 Dart VM、dart2js、Pub、库和工具。
- Dartium:内嵌 Dart VM 的 Chromium ,可以在浏览器中直接执行 dart 代码。
- Dart2js:将 Dart 代码编译为 JavaScript 的工具。
- Dart Editor:基于 Eclipse 的全功能 IDE,并包含以上所有工具。支持代码补全、代码导航、快速修正、重构、调试等功能。
关键字(56个)
关键字 | - | - | - |
---|---|---|---|
abstract | do | import | super |
as | dynamic | in | switch |
assert | else | interface | sync |
enum | implements | is | this |
async | export | library | throw |
await | external | mixin | true |
break | extends | new | try |
case | factory | null | typedef |
catch | false | operator | var |
class | final | part | void |
const | finally | rethrow | while |
continue | for | return | with |
covariant | get | set | yield |
default | if | static | deferred |
变量与常量
- 变量声明与初始化
- 调用的变量name包含对String值为“张三” 的对象的引用,name推断变量的类型是String,但可以通过指定它来更改该类型,如果对象不限于单一类型(没有明确的类型),请使用Object或dynamic关键字。
// 没有明确类型,编译的时候根据值明确类型
var name = ‘Bob’;
Object name = '张三';
dynamic name = '李四';
// 显示声明将被推断类型, 可以使用String显示声明字符串类型
String name = 'Bob' ;
- 默认值
- 未初始化的变量的初始值为null(包括数字),因此数字、字符串都可以调用各种方法
//测试 数字类型的初始值是什么?
int lineCount;
// 为false的时候抛出异常
assert(lineCount == null);
print(lineCount); //打印结果为null,证明数字类型初始化值是null
-
final and const
-
如果您从未打算更改一个变量,那么使用 final 或 const,不是var,也不是一个类型。 一个 final 变量只能被初始化一次; const变量是一个编译时常量,(Const变量是隐式的final) final的顶级或类变量在第一次使用时被初始化。
-
被final修饰的顶级变量或类变量在第一次声明的时候就需要初始化。
// The final variable 'outSideFinalName' must be initialized. final String outSideFinalName
- 被final或者const修饰的变量,变量类型可以省略,建议指定数据类型。
//可以省略String这个类型声明 final name = "Bob"; final String name1 = "张三"; const name2 = "alex"; const String name3 = "李四";
- 被 final 或 const 修饰的变量无法再去修改其值。
final String outSideFinalName = "Alex"; // outSideFinalName', a final variable, can only be set once // 一个final变量,只能被设置一次。 outSideFinalName = "Bill"; const String outSideName = 'Bill'; // 这样写,编译器提示:Constant variables can't be assigned a value // const常量不能赋值 // outSideName = "小白";
- flnal 或者 const 不能和 var 同时使用
// Members can't be declared to be both 'const' and 'var' const var String outSideName = 'Bill'; // Members can't be declared to be both 'final' and 'var' final var String name = 'Lili';
- 常量如果是类级别的,请使用 static const
// 常量如果是类级别的,请使用 static const static const String name3 = 'Tom'; // 这样写保存 // Only static fields can be declared as const // 只有静态字段可以声明为const //const String name3 = 'Tom';
- 常量的运算
const speed = 100; //速度(km/h) const double distance = 2.5 * speed; // 距离 = 时间 * 速度 final speed2 = 100; //速度(km/h) final double distance2 = 2.5 * speed2; // 距离 = 时间 * 速度
- const关键字不只是声明常数变量,您也可以使用它来创建常量值,以及声明创建常量值的构造函数,任何变量都可以有一个常量值。
// 注意: [] 创建的是一个空的list集合 // const []创建一个空的、不可变的列表(EIL)。 var varList = const []; // varList 当前是一个EIL final finalList = const []; // finalList一直是EIL const constList = const []; // constList 是一个编译时常量的EIL // 可以更改非final,非const变量的值 // 即使它曾经具有const值 varList = ["haha"]; // 不能更改final变量或const变量的值 // 这样写,编译器提示:a final variable, can only be set once // finalList = ["haha"]; // 这样写,编译器提示:Constant variables can't be assigned a value // constList = ["haha"];
- 在常量表达式中,该运算符的操作数必须为'bool'、'num'、'String'或'null', const常量必须用conat类型的值初始化。
const String outSideName = 'Bill'; final String outSideFinalName = 'Alex'; const String outSideName2 = 'Tom'; const aConstList = const ['1', '2', '3']; // In constant expressions, operands of this operator must be of type 'bool', 'num', 'String' or 'null' // 在常量表达式中,该运算符的操作数必须为'bool'、'num'、'String'或'null'。 const validConstString = '$outSideName $outSideName2 $aConstList'; // Const variables must be initialized with a constant value // const常量必须用conat类型的值初始化 const validConstString = '$outSideName $outSideName2 $outSideFinalName'; var outSideVarName='Cathy'; // Const variables must be initialized with a constant value. // const常量必须用conat类型的值初始化 const validConstString = '$outSideName $outSideName2 $outSideVarName'; // 正确写法 const String outSideConstName = 'Joy'; const validConstString = '$outSideName $outSideName2 $outSideConstName';
-
数据类型
-
num
-
num 是数字类型的父类,有两个子类 int 和 double。
-
int 根据平台的不同,整数值不大于64位。在Dart VM上,值可以从-263到263 - 1,编译成JavaScript的Dart使用JavaScript代码,允许值从-253到253 - 1。
-
double 64位(双精度)浮点数,如IEEE 754标准所规定。
int a = 1; print(a); double b = 1.12; print(b); // String -> int int one = int.parse('1'); // 输出3 print(one + 2); // String -> double var onePointOne = double.parse('1.1'); // 输出3.1 print(onePointOne + 2); // int -> String String oneAsString = 1.toString(); // The argument type 'int' can't be assigned to the parameter type 'String' //print(oneAsString + 2); // 输出 1 + 2 print('$oneAsString + 2'); // 输出 1 2 print('$oneAsString 2'); // double -> String 注意括号中要有小数点位数,否则报错 String piAsString = 3.14159.toStringAsFixed(2); // 截取两位小数, 输出3.14 print(piAsString); String aString = 1.12618.toStringAsFixed(2); // 检查是否四舍五入,输出1.13,发现会做四舍五入 print(aString);
-
-
String
-
Dart里面的String是一系列 UTF-16 代码单元。
-
Dart里面的String是一系列 UTF-16 代码单元。
-
单引号或者双引号里面嵌套使用引号。
-
用 或{} 来计算字符串中变量的值,需要注意的是如果是表达式需要${表达式}
String singleString = 'abcdddd'; String doubleString = "abcsdfafd"; String sdString = '$singleString a "bcsd" ${singleString}'; String dsString = "abc 'aaa' $sdString"; print(sdString); print(dsString); String singleString = 'aaa'; String doubleString = "bbb"; // 单引号嵌套双引号 String sdString = '$singleString a "bbb" ${doubleString}'; // 输出 aaa a "bbb" bbb print(sdString); // 双引号嵌套单引号 String dsString = "${singleString.toUpperCase()} abc 'aaa' $doubleString.toUpperCase()"; // 输出 AAA abc 'aaa' bbb.toUpperCase(), 可以看出 ”$doubleString.toUpperCase()“ 没有加“{}“,导致输出结果是”bbb.toUpperCase()“ print(dsString);
-
-
bool
- Dart 是强 bool 类型检查,只有bool 类型的值是true 才被认为是true。
- 只有两个对象具有bool类型:true和false,它们都是编译时常量。
- Dart的类型安全意味着您不能使用 if(nonbooleanValue) 或 assert(nonbooleanValue) 等代码, 相反Dart使用的是显式的检查值。
- assert 是语言内置的断言函数,仅在检查模式下有效在开发过程中, 除非条件为真,否则会引发异常。(断言失败则程序立刻终止)。
// 检查是否为空字符串 var fullName = ''; assert(fullName.isEmpty); // 检查0 var hitPoints = 0; assert(hitPoints <= 0); // 检查是否为null var unicorn; assert(unicorn == null); // 检查是否为NaN var iMeantToDoThis = 0 / 0; assert(iMeantToDoThis.isNaN);
-
List集合
- 在Dart中,数组是List对象,因此大多数人只是将它们称为List。Dart list文字看起来像JavaScript数组文字
//创建一个int类型的list List list = [10, 7, 23]; // 输出[10, 7, 23] print(list); // 使用List的构造函数,也可以添加int参数,表示List固定长度,不能进行添加 删除操作 var fruits = new List(); // 添加元素 fruits.add('apples'); // 添加多个元素 fruits.addAll(['oranges', 'bananas']); List subFruits = ['apples', 'oranges', 'banans']; // 添加多个元素 fruits.addAll(subFruits); // 输出: [apples, oranges, bananas, apples, oranges, banans] print(fruits); // 获取List的长度 print(fruits.length); // 获取第一个元素 print(fruits.first); // 获取元素最后一个元素 print(fruits.last); // 利用索引获取元素 print(fruits[0]); // 查找某个元素的索引号 print(fruits.indexOf('apples')); // 删除指定位置的元素,返回删除的元素 print(fruits.removeAt(0)); // 删除指定元素,成功返回true,失败返回false // 如果集合里面有多个“apples”, 只会删除集合中第一个改元素 fruits.remove('apples'); // 删除最后一个元素,返回删除的元素 fruits.removeLast(); // 删除指定范围(索引)元素,含头不含尾 fruits.removeRange(start,end); // 删除指定条件的元素(这里是元素长度大于6) fruits.removeWhere((item) => item.length >6); // 删除所有的元素 fruits.clear();
-
注意事项:
- 可以直接打印list包括list的元素,list也是一个对象。但是java必须遍历才能打印list,直接打印是地址值。
- 和java一样list里面的元素必须保持类型一致,不一致就会报错。
- 和java一样list的角标从0开始。
- 如果集合里面有多个相同的元素“X”, 只会删除集合中第一个改元素
-
Map集合
- 一般来说,map是将键和值相关联的对象。键和值都可以是任何类型的对象。每个键只出现一次,但您可以多次使用相同的值。Dart支持map由map文字和map类型提供。
- 初始化Map方式一: 直接声明,用{}表示,里面写key和value,每组键值对中间用逗号隔开。
// Two keys in a map literal can't be equal. // Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度', 'Alibaba': '钉钉', 'Tenect': 'qq-music'}; Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度'}; // 输出:{Alibaba: 阿里巴巴, Tencent: 腾讯, baidu: 百度} print(companys);
- 创建Map方式二:先声明,再去赋值。
Map schoolsMap = new Map(); schoolsMap['first'] = '清华'; schoolsMap['second'] = '北大'; schoolsMap['third'] = '复旦'; // 打印结果 {first: 清华, second: 北大, third: 复旦} print(schoolsMap); var fruits = new Map(); fruits["first"] = "apple"; fruits["second"] = "banana"; fruits["fifth"] = "orange"; //换成双引号,换成var 打印结果 {first: apple, second: banana, fifth: orange} print(fruits);
- Map API
// 指定键值对的参数类型 var aMap = new Map<int, String>(); // Map的赋值,中括号中是Key,这里可不是数组 aMap[1] = '小米'; //Map中的键值对是唯一的 //同Set不同,第二次输入的Key如果存在,Value会覆盖之前的数据 aMap[1] = 'alibaba'; // map里面的value可以相同 aMap[2] = 'alibaba'; // map里面value可以为空字符串 aMap[3] = ''; // map里面的value可以为null aMap[4] = null; print(aMap); // 检索Map是否含有某Key assert(aMap.containsKey(1)); //删除某个键值对 aMap.remove(1); print(aMap);
- 注意事项
- map的key类型不一致也不会报错。
- 添加元素的时候,会按照你添加元素的顺序逐个加入到map里面,哪怕你的key,比如分别是 1,2,4,看起来有间隔,事实上添加到map的时候是{1:value,2:value,4:value} 这种形式。
- map里面的key不能相同。但是value可以相同,value可以为空字符串或者为null。
运算符
描述 | 操作符 |
---|---|
一元后置操作符 | expr++ expr-- () [] . ?. |
一元前置操作符 | expr !expr ~expr ++expr --expr |
乘除 | * / % ~/ |
加减 | + - |
位移 | << >> |
按位与 | & |
按位或 | |
按位异或 | ^ |
逻辑与 | && |
逻辑或 | |
关系和类型判断 | >= > <= < as is is! |
等 | == != |
如果为空 | ?? |
条件表达式 | expr1 ? expr2 : expr3 |
赋值 | = *= /= ~/= %= += -= <<= >>= &= ^= = ??= |
级联 | .. |
流程控制语句(Control flow statements)
- if...else
- for
- while do-whild
- break continue
- break continue
- assert(仅在checked模式有效)
异常(Exceptions)
-
throw
- 抛出固定类型的异常
throw new FormatException('Expected at least 1 section');
- 抛出任意类型的异常
throw 'Out of llamas!';
- 因为抛出异常属于表达式,可以将throw语句放在=>语句中,或者其它可以出现表达式的地方
distanceTo(Point other) => throw new UnimplementedError();
-
catch
- 将可能出现异常的代码放置到try语句中,可以通过 on语句来指定需要捕获的异常类型,使用catch来处理异常。
try { breedMoreLlamas(); } on OutOfLlamasException { // A specific exception buyMoreLlamas(); } on Exception catch (e) { // Anything else that is an exception print('Unknown exception: $e'); } catch (e, s) { print('Exception details:\n $e'); print('Stack trace:\n $s'); }
-
rethrow
- rethrow语句用来处理一个异常,同时希望这个异常能够被其它调用的部分使用。
final foo = ''; void misbehave() { try { foo = "1"; } catch (e) { print('2'); rethrow;// 如果不重新抛出异常,main函数中的catch语句执行不到 } } void main() { try { misbehave(); } catch (e) { print('3'); } }
-
finally
- Dart的finally用来执行那些无论异常是否发生都执行的操作。
final foo = ''; void misbehave() { try { foo = "1"; } catch (e) { print('2'); } } void main() { try { misbehave(); } catch (e) { print('3'); } finally { print('4'); // 即使没有rethrow最终都会执行到 } }
函数 Function
- 以下是一个实现函数的例子:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
-
main()函数
- 每个应用程序都必须有一个顶层main()函数,它可以作为应用程序的入口点。该main()函数返回void并具有List参数的可选参数。
void main() { querySelector('#sample_text_id') ..text = 'Click me!' ..onClick.listen(reverseText); }
- 级联符号..允许您在同一个对象上进行一系列操作。除了函数调用之外,还可以访问同一对象上的字段。这通常会为您节省创建临时变量的步骤,并允许您编写更流畅的代码。
querySelector('#confirm') // Get an object. ..text = 'Confirm' // Use its members. ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed!'));
- 上述例子相对于:
var button = querySelector('#confirm'); button.text = 'Confirm'; button.classes.add('important'); button.onClick.listen((e) => window.alert('Confirmed!'));
- 级联符号也可以嵌套使用。 例如:
final addressBook = (AddressBookBuilder() ..name = 'jenny' ..email = '[email protected]' ..phone = (PhoneNumberBuilder() ..number = '415-555-0100' ..label = 'home') .build()) .build();
- 当返回值是void时不能构建级联。 例如,以下代码失败:
var sb = StringBuffer(); sb.write('foo') // 返回void ..write('bar'); // 这里会报错
- 注意: 严格地说,级联的..符号不是操作符。它只是Dart语法的一部分。
-
可选参数
- 可选的命名参数, 定义函数时,使用{param1, param2, …},用于指定命名参数。例如:
//设置[bold]和[hidden]标志 void enableFlags({bool bold, bool hidden}) { // ... } enableFlags(bold: true, hidden: false);
- 可选的位置参数,用[]它们标记为可选的位置参数:
String say(String from, String msg, [String device]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } return result; }
- 下面是一个不带可选参数调用这个函数的例子:
say('Bob', 'Howdy'); //结果是: Bob says Howdy
- 下面是用第三个参数调用这个函数的例子:
say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
-
默认参数
- 函数可以使用=为命名参数和位置参数定义默认值。默认值必须是编译时常量。如果没有提供默认值,则默认值为null。
- 下面是为命名参数设置默认值的示例:
// 设置 bold 和 hidden 标记的默认值都为false void enableFlags2({bool bold = false, bool hidden = false}) { // ... } // 调用的时候:bold will be true; hidden will be false. enableFlags2(bold: true);
- 下一个示例显示如何为位置参数设置默认值:
String say(String from, String msg, [String device = 'carrier pigeon', String mood]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } if (mood != null) { result = '$result (in a $mood mood)'; } return result; } //调用方式: say('Bob', 'Howdy'); //结果为:Bob says Howdy with a carrier pigeon;
- 您还可以将list或map作为默认值传递。下面的示例定义一个函数doStuff(),该函数指定列表参数的默认list和gifts参数的默认map。
// 使用list 或者map设置默认值 void doStuff( {List<int> list = const [1, 2, 3], Map<String, String> gifts = const {'first': 'paper', 'second': 'cotton', 'third': 'leather' }}) { print('list: $list'); print('gifts: $gifts'); }
-
作为一个类对象的功能
- 您可以将一个函数作为参数传递给另一个函数。
void printElement(int element) { print(element); } var list = [1, 2, 3]; // 把 printElement函数作为一个参数传递进来 list.forEach(printElement);
- 您也可以将一个函数分配给一个变量。
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!'; assert(loudify('hello') == '!!! HELLO !!!');
-
匿名函数
- 大多数函数都能被命名为匿名函数,如 main() 或 printElement()。您还可以创建一个名为匿名函数的无名函数,有时也可以创建lambda或闭包。您可以为变量分配一个匿名函数,例如,您可以从集合中添加或删除它。
- 一个匿名函数看起来类似于一个命名函数 - 0或更多的参数,在括号之间用逗号和可选类型标注分隔。
- 下面的代码块包含函数的主体:
([[Type] param1[, …]]) { codeBlock; };
- 下面的示例定义了一个具有无类型参数的匿名函数item,该函数被list中的每个item调用,输出一个字符串,该字符串包含指定索引处的值。
var list = ['apples', 'bananas', 'oranges']; list.forEach((item) { print('${list.indexOf(item)}: $item'); });
- 如果函数只包含一条语句,可以使用箭头符号=>来缩短它, 比如上面的例2可以简写成:
list.forEach((item) => print('${list.indexOf(item)}: $item'));
-
返回值
- 所有函数都返回一个值,如果没有指定返回值,则语句return null,隐式地附加到函数体。
foo() {} assert(foo() == null);
类(Classes)
-
对象
- Dart 是一种面向对象的语言,并且支持基于mixin的继承方式。
- Dart 语言中所有的对象都是某一个类的实例,所有的类有同一个基类--Object。
- 基于mixin的继承方式具体是指:一个类可以继承自多个父类。
- 使用new语句来构造一个类,构造函数的名字可能是ClassName,也可以是ClassName.identifier, 例如:
var jsonData = JSON.decode('{"x":1, "y":2}'); // Create a Point using Point(). var p1 = new Point(2, 2); // Create a Point using Point.fromJson(). var p2 = new Point.fromJson(jsonData);
- 使用.(dot)来调用实例的变量或者方法。
var p = new Point(2, 2); // Set the value of the instance variable y. p.y = 3; // Get the value of y. assert(p.y == 3); // Invoke distanceTo() on p. num distance = p.distanceTo(new Point(4, 4));
- 使用?.来确认前操作数不为空, 常用来替代. , 避免左边操作数为null引发异常。
// If p is non-null, set its y value to 4. p?.y = 4;
- 使用const替代new来创建编译时的常量构造函数。
var p = const ImmutablePoint(2, 2);
- 使用runtimeType方法,在运行中获取对象的类型。该方法将返回Type 类型的变量。
print('The type of a is ${a.runtimeType}');
-
实例化变量(Instance variables)
- 在类定义中,所有没有初始化的变量都会被初始化为null。
class Point { num x; // Declare instance variable x, initially null. num y; // Declare y, initially null. num z = 0; // Declare z, initially 0. }
- 类定义中所有的变量, Dart语言都会隐式的定义 setter 方法,针对非空的变量会额外增加 getter 方法。
class Point { num x; num y; } main() { var point = new Point(); point.x = 4; // Use the setter method for x. assert(point.x == 4); // Use the getter method for x. assert(point.y == null); // Values default to null. }
-
构造函数(Constructors)
- 声明一个和类名相同的函数,来作为类的构造函数。
class Point { num x; num y; Point(num x, num y) { // There's a better way to do this, stay tuned. this.x = x; this.y = y; } }
- this关键字指向了当前类的实例, 上面的代码可以简化为:
class Point { num x; num y; // Syntactic sugar for setting x and y // before the constructor body runs. Point(this.x, this.y); }
-
构造函数不能继承(Constructors aren’t inherited)
- Dart 语言中,子类不会继承父类的命名构造函数。如果不显式提供子类的构造函数,系统就提供默认的构造函数。
-
命名的构造函数(Named constructors)
- 使用命名构造函数从另一类或现有的数据中快速实现构造函数。
class Point { num x; num y; Point(this.x, this.y); // 命名构造函数Named constructor Point.fromJson(Map json) { x = json['x']; y = json['y']; } }
- 构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类是实现这个构造函数。
-
调用父类的非默认构造函数
-
默认情况下,子类只能调用父类的无名,无参数的构造函数; 父类的无名构造函数会在子类的构造函数前调用; 如果initializer list 也同时定义了,则会先执行initializer list 中的内容,然后在执行父类的无名无参数构造函数,最后调用子类自己的无名无参数构造函数。即下面的顺序:
- initializer list(初始化列表)
- super class’s no-arg constructor(父类无参数构造函数)
- main class’s no-arg constructor (主类无参数构造函数)
-
如果父类不显示提供无名无参数构造函数的构造函数,在子类中必须手打调用父类的一个构造函数。这种情况下,调用父类的构造函数的代码放在子类构造函数名后,子类构造函数体前,中间使用:(colon) 分割。
class Person { String firstName; Person.fromJson(Map data) { print('in Person'); } } class Employee extends Person { // 父类没有无参数的非命名构造函数,必须手动调用一个构造函数 super.fromJson(data) Employee.fromJson(Map data) : super.fromJson(data) { print('in Employee'); } } main() { var emp = new Employee.fromJson({}); // Prints: // in Person // in Employee if (emp is Person) { // Type check emp.firstName = 'Bob'; } (emp as Person).firstName = 'Bob'; }
-
-
初始化列表
- 除了调用父类的构造函数,也可以通过初始化列表在子类的构造函数体前(大括号前)来初始化实例的变量值,使用逗号,分隔。如下所示:
class Point { num x; num y; Point(this.x, this.y); // 初始化列表在构造函数运行前设置实例变量。 Point.fromJson(Map jsonMap) : x = jsonMap['x'], y = jsonMap['y'] { print('In Point.fromJson(): ($x, $y)'); } }
注意:上述代码,初始化程序无法访问 this 关键字。
-
静态构造函数
- 如果你的类产生的对象永远不会改变,你可以让这些对象成为编译时常量。为此,需要定义一个 const 构造函数并确保所有的实例变量都是 final 的。
class ImmutablePoint { final num x; final num y; const ImmutablePoint(this.x, this.y); static final ImmutablePoint origin = const ImmutablePoint(0, 0); }
-
重定向构造函数
- 有时候构造函数的目的只是重定向到该类的另一个构造函数。重定向构造函数没有函数体,使用冒号:分隔。
class Point { num x; num y; // 主构造函数 Point(this.x, this.y) { print("Point($x, $y)"); } // 重定向构造函数,指向主构造函数,函数体为空 Point.alongXAxis(num x) : this(x, 0); } void main() { var p1 = new Point(1, 2); var p2 = new Point.alongXAxis(4); }
-
常量构造函数
- 如果类的对象不会发生变化,可以构造一个编译时的常量构造函数。定义格式如下:
- 定义所有的实例变量是final。
- 使用const声明构造函数。
class ImmutablePoint { final num x; final num y; const ImmutablePoint(this.x, this.y); static final ImmutablePoint origin = const ImmutablePoint(0, 0); }
- 如果类的对象不会发生变化,可以构造一个编译时的常量构造函数。定义格式如下:
-
工厂构造函数
- 当实现一个使用 factory 关键词修饰的构造函数时,这个构造函数不必创建类的新实例。例如,工厂构造函数可能从缓存返回实例,或者它可能返回子类型的实例。 下面的示例演示一个工厂构造函数从缓存返回的对象:
全部评论
请发表评论