代码风格

代码风格建议参考Effective Dart规范
http://dart.goodev.org/guides/language/effective-dart/style

基础语法

https://dart.dev/guides/language/language-tour

在学习Dart语言时,需要记住的一些概念:

  • 在Dart中,所有能够使用变量引用的,都是对象,每个对象都是一个类的实例;数字、方法和null都是对象。所有的对象都继承至Object类。
  • 很多时候,使用静态类型可以更清晰地表达你地意图。
  • Dart没有public、protected、private关键字,如果一个标识符是以(_)开头,则标识符在库内是私有地。

内置类型(Built-in types)

  • numbers
  • strings
  • booleans
  • list(也被称为arrays)
  • maps
  • runes(用于在字符串中表示Unicode字符)
  • symbols

Functions

因为Dart是真正的面向对象语言,因此,方法也是对象,并且有一种类型 Function。这意味着方法可以赋值给变量,也可以当作其他方法的参数。也可以把Dart类的实例当作方法来调用。

Classes

构造函数

定义一个和类名字一样的方法就定义了一个构造函数。

  1. class Point {
  2. num x;
  3. num y;
  4. Point(num x, num y) {
  5. this.x = x;
  6. this.y = y;
  7. }
  8. }

this关键字指向当前的实例。
由于把构造函数参数赋值给实例变量的场景非常普遍,因此Dart提供了一个语法糖来简化赋值操作,如下所示:

  1. class Point {
  2. num x;
  3. num y;
  4. Point(this.x, this.y);
  5. }
  • 如果没有定义构造函数,则会有一个默认构造函数。默认构造函数是没有参数的,并且会调用超类中的没有参数的构造函数。
  • 子类不会继承超类的构造函数。子类如果没有定义构造函数,则只有一个默认的构造函数(没有名字没有参数)。
  • 使用命名构造函数可以为一个类实现多个构造函数,或者使用命名构造函数还更清晰地表明你的意图。

注意:构造函数不能被继承,所以超类的命名构造函数也不会被继承。如果希望子类也有超类一样的命名函数,必须在子类中自己实现该构造函数。

Dart库的引入

指定库前缀解决冲突

当两个库具有冲突的标识符时,可以使用库前缀进行区分。例如:library A和library B都具有同通名称的类,那么可以用如下方式进行区分。

  1. import 'package:libA/libA.dart' as libA;
  2. import 'package:libB/libB.dart' as libB;
  3. libA.Element element1 = new Element(); // 使用libA中的Element类
  4. libB.Element element2 = new Element(); // 使用libB中的Element类

显示或屏蔽内容

如果只想使用库的一部分功能,则可以选择需要导入/屏蔽的内容,例如:

  1. // Import only foo.
  2. import 'package:libA/libA.dart' show foo;
  3. // Import all names EXCEPT foo.
  4. import 'package:libB/libB.dart' hide foo;

库的懒加载

Dart库懒加载可以让应用在必要的时候才加载库。以下是延迟加载库的一些场景:

  • 减少APP的启动时间。
  • 执行A/B testing的时候,例如:尝试不同算法和实现。
  • 加载很少使用的功能时。

要延迟加载一个库,需要先使用 deferred as 来导入:

  1. import 'package:deferred/hello.dart' deferred as hello;

当需要使用的时候,使用库标识符调用loadLibrary()函数来加载库:

  1. greet() async {
  2. await hello.loadLibrary();
  3. hello.printGreeting();
  4. }

上面的代码中,使用 asyncawait 组合来暂停代码的执行,直到库加载完成。在一个库上,可以多次调用loadLibrary() 函数,但是库只被加载一次。

在延迟加载库时,需要注意的问题如下:

  • 延迟加载库中定义的常量在导入的时候是不可用的,因此,只有当库加载完毕之后,库中常量才能使用。
  • 在导入文件时无法使用延迟库中的类型。
  • Dart隐含的把loadLibrary()函数导入到使用 deferred as 的命名空间中。loadLibrary()方法返回一个Future。

可调用类

如果Dart类实现了 call() 函数,则可以当作方法来调用。
参考:http://dart.goodev.org/articles/language/emulating-functions

Isolates

现代浏览器及移动端浏览器都运行在多核CPU系统上。如果需要充分利用这些CPU,开发者一般使用共享内存数据来保证多线程的正确执行,然而,多线程共享数据通常会有很多潜在问题,且导致代码运行出错。
在Dart中,代码在isoloate中运行,而不是在线程中运行。每个isolate都有自己的堆内存,并且确保每个isolate的状态都不能被其他isolate访问。

元数据(Metadata)

使用元数据可以为代码添加额外的信息。元数据注解以@字符开头,后面是一个编译时常量(例如:deprecated)或调用一个常量构造函数。
有三个注解所有的Dart代码都可以使用:

  • deprecated
  • override
  • proxy

    自定义元数据

    用户可以自定义元数据: ```dart library slogan;

class slogan { final String who; final String what;

const slogan(this.who, this.what); }

  1. 使用注解示例:
  2. ```dart
  3. import 'slogan.dart';
  4. @slogan('Trump', 'Make American greate again!')
  5. void election() {
  6. // add codes ...
  7. }