语言概述

  • Dart 语言在2011年10月由 Google 发布的网络编程语言,并在2012年10月发布第一个里程碑版本M1,2015年5月Google公开了基于Dart语言的移动应用程序开发框架Sky,后更名为Flutter
  • Flutter是一个使用Dart语言开发的跨平台移动UI框架,渲染引擎依赖Skia图形库实现,在Flutter中的控件树编译为高性能的本地ARM代码直接绘制。Dart是Flutter的主要开发语言 ,支持JIT编译(开发阶段可热重载)和AOT编译(Release运行阶段性能好)
  • Dart可利用隔离区(Isolate)实现多线程,且不共享内存,实现无锁快速分配
  • Dart采用分代垃圾回收机制,且在创建对象分配内存时,是在现有堆上移动指针,保证内存增长是线性的,有利于UI框架中大量Widgets对象的创建和销毁优化
  • Dart是面向对象的、类定义的、单继承的语言,一切都是对象(包括基本类型,函数,null),所有对象都继承自Object
  • Dart是强类型语言,但也自带类型推断
  • Dart中没有public,private,protected,默认都是public的,可以通过_开头指定是库私有的
  • Dart支持顶级变量(不与类绑定)和顶级函数(如main函数)

变量

Dart为强类型语言,变量可显式声明,也可自动推断,但推断出来后,该变量的类型将不再改变,若要让变量不被限制于一种类型,可将变量声明为dynamic或Object

类型

  • 数字num
    int: 平台的不同,范围也不同。整数值不大于64位。在Dart VM上,值可以从-263到263 - 1
    double: 64位(双精度)浮点数
    数字和字符串转换:
int.parse('1') 
3.14159.toStringAsFixed(2);
  • 字符串String
    String是UTF-16编码单元的序列,可以使用${expression}将表达式的值放入字符串中。如果表达式是一个标识符,可以不用{},
String str = "world";
print("hello$str");

可以用三重引号创建多行字符串,用r前缀创建一个原始字符串(不会因为有\n换行)

var s = r'In a raw string, not even \n gets special treatment.';
print(s); //虽然有换行符,但输出不会换行
  • 布尔型(bool):true, false
  • 列表List
    数组即为列表对象
var list = [1,2,3];  //推断为List<int> 类型,若添加非int对象,则会报错
  • 映射Map
    可以通过map字面量直接创建,也可以通过Map()构造方法创建, 类型会自动推断
var g = { 1: 'a', 2: 'b', 3: 'c'}
var g1 = Map();
g1[1] = 'a1'
final constantMap = const {2: 'b', 3: 'c'};
  • 字符Runes:
    字符是字符串的UTF-32编码
  • 符号Symbols:
print(#bar) 
// 输出 Symbol("bar")

变量声明

Dart没有public protected private等关键字,如果某个变量以下划线开头,代表这个变量是私有的

String me = "Bob";  // 显式name变量声明为String
var you = "Bob";   // 自动推断name变量为String
dynamec he = “Bob”;   // 声明变量为任意类型,类似于java中Object
he = 18;   
int u;  // 未初始化的变量初始值为null,变量存放的是对象,对象都继承自Object类
final a;  // 最终变量,只能设置一次,顶级或类变量在第一次使用时被初始化
const b = 9;  // 编译时常量,定义时必须赋值。注意实例变量可以是final,但不能是const。
var f = const[];
f = [1,3];   // 可以更改一个非final的且非const变量的值,即使它曾经有一个const值

运算符

相等(==)

若两者都为空则返回true,若只有一空返回false;
需要知道两个对象是否完全相同的情况下,可以使用identical()函数

类型判断(is)

若obj 实现了T,则 obj is T 为真

类型转换(as)

as操作符将对象转换为特定类型

非空赋值(??=)

b ??= value;  //仅仅在b为空的情况下b被赋值value否则b的值不变

条件表达(??)

expr1 ?? expr2 ; //如果expr1是非空的,则返回其值,否则,计算并返回expr2的值

级联(..)

在同一个对象上创建一个操作序列。可以访问同一对象上的字段,调用函数,省去创建临时变量的步骤。
不能在一个返回void结果上继续构建级联操作

querySelector('#confirm') // 获取一个对象
  ..text = 'Confirm' // 使用它的成员
  ..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!'));

条件成员访问(?.)

如果左边的操作对象为null则返回null,否则返回右边的成员

函数

函数也是对象,可以赋给函数,也可以赋给变量,甚至可以是函数的返回值。函数可以省略返回类型声明(可以根据return自动推断),所有函数都默认返回null(没有return语句)

函数简写

isBelowZero(int n) => n < 0; //只包含一个表达式的函数简写

命名参数

在定义函数时,使用{param1, param2,…}来指定命名参数

void enableFlags({bool bold, bool hidden}) {...}
enableFlags(bold: true, hidden: false);

可选参数

在普通的位置参数里,可以通过[]包装为一组可选参数,在命名参数里,可以通过@required标识必传参数,其他都是可选的。

say(String from, String msg, [String device])
Scrollbar({Key key, @required Widget child})

默认参数

用 = 来定义参数的默认值。默认值必须是编译时常量。如果没有提供默认值,则默认值为null

void enableFlags({bool bold = false, bool hidden = false})

main()函数

应用程序的入口点。返回void,并有一个可选的列表参数作为参数

void main(List<String> arguments) {
  print(arguments);
  assert(arguments.length == 2);
  assert(int.parse(arguments[0]) == 1);
  assert(arguments[1] == 'test');
}

匿名函数

 ([[Type] param1[, …]]) {
    codeBlock;
 };

函数类型

typedef为函数提供一个类型别名

typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
assert(sort is Compare<int>); // True!
}

流程控制

循环迭代

//若对象是可迭代的
candidates.forEach((candidate) => candidate.interview());
//List和Set等支持for in迭代
for (var x in collection) { }

过滤器where

即使where筛选后为空也没问题,只是不会执行后面的forEach

candidates
 .where((c) => c.yearsExperience >= 5)
 .forEach((c) => c.interview());

switch

每个非空的case子句以一个break语句结束,否则会报错,default 可以没有。

类和库

Dart值支持单继承,所有类都是Object的子类,支持泛型。库的导入用import

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;  //导入有冲突时指定前缀
import 'package:lib1/lib1.dart' show foo; //只导入foo
import 'package:lib2/lib2.dart' hide foo; //除了foo其他导入
import 'package:greetings/hello.dart' deferred as hello; //延时加载
Future greet() async {
  await hello.loadLibrary(); //需要时加载,可以在库上多次调用loadLibrary()。该库只加载一次
  hello.printGreeting();
}

类实现call方法,则可以通过类对象直接调用函数

class WannabeFunction {
  call(String a, String b, String c) => '$a $b $c!';
}
var wf = new WannabeFunction();
var out = wf("Hi", "there,", "gang");
print('$out');

异步

async和await

通过将函数体用async修饰符标记,将使其返回一个Future,声明异步函数。如果异步函数没有返回一个有用的值,那么将其返回Future类型。await必须是在一个使用async标注的异步函数使用,await表达式会让程序执行挂起,直到返回的对象可用。在await表达式中,表达式的值通常是一个Future对象。如果不是,那么这个值将被自动包装成Future

String lookUpVersionSync() => '1.0.0';  //同步函数
Future<String> lookUpVersionAsync() async => '1.0.0';; //异步函数
Future checkVersion() async {
  var version = await lookUpVersionAsync();
}

隔离器(Isolate)

不同于线程,所有Dart代码都运行在隔离器内部,而不是线程。每个隔离都有它自己的内存堆,确保任何其他隔离器都不能访问隔离状态