不止前端
首发于不止前端

Dart语言官网翻译上

依照当前官网最新2.5.2版本翻译并精简,括号里的许多内容是自己放进去的评论,如果你有Java和JavaScript(ES6)基础,理解Dart就不会困难。

简单起见,可以使用在线的DartPad来尝试Dart语言。

基本的Dart程序

// 定义一个方法
printInteger(int aNumber) {
  print('The number is $aNumber.'); // 打印到console上
}

// 应用开始执行的地方
main() {
  var number = 42; // 声明并初始化变量
  printInteger(number); // 调用方法
}

重要的概念

  • Dart里所有的变量都是对象,每个对象都是类的实例(跟现代语言很相似,不再有基础类型了)。即便是数字、方法、null都是对象。所有的对象都继承自Object类。
  • 尽管Dart是强类型,类型声明却是可选的,因为Dart可以推断(现代语言或者新版本比如Java10也都具备该能力)。上面的例子中number被推断为int类型。如果你想明确变量是没有类型的,就用dynamic来声明。
  • Dart支持泛型,比如List<int>或者List<dynamic>。
  • Dart支持顶层方法,比如main( ),也支持绑定在类和对象上的方法(静态和实例方法)。你也可以在方法里再定义方法。
  • Dart支持顶层变量,以及绑定在类和对象上的变量。实例变量也被称之为field或property(特意不翻译)。
  • 跟Java不同,Dart没有public、protected、private等关键字。如果一个变量名用_开头,它就是私有的。
  • 变量名用字母或者下划线_开头,剩余部分可以是字母、下划线或数字。
  • Dart既有表达式(它有运行时值)也有语句(没有运行时值)。比如condition ? expr1 : expr2有expr1和expr2的值。与if-else语句比较,if-else就没有。一条语句可能含有一个或多个表但是,但表达式不会直接包含语句。
  • Dart工具会报告两种问题:警告和错误。警告一般说明你的代码可能不工作,但不会阻止运行。错误要么是编译时错误或者运行时错误。编译时错误会阻止代码运行,运行时错误会在执行的时候抛出异常。

关键词

略(知乎里怎么插入表格呢?)

变量

var name = 'Bob';

变量存储的是引用。这个叫name的变量指向一个字符串对象,值是"Bob"。

name变量就被推断为字符串类型,你可以显式指定类型来修改,如果用dynamic声明能让变量不限制为某一种类型。

dynamic name = 'Bob';

另一种显式声明的方式是

String name = 'Bob';

默认值

没有初始化的变量有null的初始值。即便是数字类型的变量的初始值也是null,因为Dart里万物皆对象。

int lineCount;
assert(lineCount == null); //生产环境会忽略assert,但开发环境在断言为false时会抛异常

Final和const

如果不打算修改变量的值,就使用final或者const。final的变量只能被设置一次,const变量是编译时常量(const的变量隐式是final的)。final的顶层或类里的变量在第一次使用的时候被初始化。

Final的实例变量必须在构造函数体之前被初始化——通过构造函数参数在变量声明时,或者在构造函数的初始化列表里(后面再提到)。

final name = 'Bob'; // 没有类型声明
final String nickname = 'Bobby';

不能修改final变量

name = 'Alice'; // Error: a final variable can only be set once.

当想要编译时常量(有点像宏,Java里有的场景下的final变量也是编译时常量)时使用const。如果是类层级上的const,就声明为static const。当声明时,可以设置值为数字或字符串字面量,const的变量或者常量数字的计算结果。

const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere

const还可以用来创建不变值(constant value)以及创建不变值的构造函数,任何变量都可以指向不变值。

var foo = const [];
final bar = const [];
const baz = []; // 与 `const []`等同
// foo bar baz这三个变量 == 判断都是true,有点像Java里的缓存池

可以改变非final非const的变量,即便它指向一个const值。

foo = [1, 2, 3]; // 原来是 const []
//当不能改变const变量的指向
baz = [42]; // Error: Constant variables can't be assigned a value.

Dart 2.5里可以对常量做类型转换(as)和判断(is)还有...扩展符号。

const Object i = 3; // 类型是Object,实际是int
const list = [i as int]; // 类型转换
const map = {if (i is int) i: "int"}; 
const set = {if (list is List<int>) ...list};

内置类型

  • numbers
  • strings
  • booleans
  • lists(arrays)
  • sets
  • maps
  • runes(为了在字符串里表示Unicode字符)
  • symbols

可以用字面量来初始化,比如'this is a string'是字符串字面量,true是布尔字面量。

由于Dart里万物皆对象,你可以使用构造函数来初始化变量。一些内置类型有自己的构造函数,比如Map( )。

数字

两种类型

int

整型值不会超过64位,依赖于平台。在Dart虚拟机里,- 2^{63}2^{63} -1之间。如果被编译为JavaScript,那范围在- 2^{53}2^{53} -1之间。

double

依照IEEE 754标准的64位浮点数。

int和double都是num的子类型。num有基本的运算比如+ - * / 。也有一些其他数学方法,比如abs( )、ceil( )、floor( )。可以在dart:math库里找到更多的运算方法。

整型是没有小数点的数字,比如

var x = 1;
var hex = 0xDEADBEEF;

有小数点就变为浮点型。

var y = 1.1;
var exponents = 1.42e5;

从Dart 2.1起,整型字面量在必要时会自动转为浮点型(Dart 2.1之前会报错)。

double z = 1; // 等同于 double z = 1.0.

下面例子是如何把字符串和数字互转。

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

整型还能做位运算。

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111

字面量是编译时常量。许多数学表达式也是编译时常量,只要他们的运算数是编译时常量就成。

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

字符串

Dart的字符串是UTF-16编码。可以用单引号或者双引号来创建字符串。

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

可以用${expression}创建插值表达式(跟JavaScript里${ }一样)。如果表达式是变量,还可以忽略{ }。Dart里也是用toString( )来把对象转为字符串。

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==
    'Dart has string interpolation, ' +
        'which is very handy.');
assert('That deserves all caps. ' +
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. ' +
        'STRING INTERPOLATION is very handy!');
==在Dart里针对字符串是比较值

也是用+来拼接字符串

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
assert(s1 ==
    'String concatenation works even over '
        'line breaks.');

var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');

用三引号来创建多行字符串。

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a
multi-line string.""";

可以用r来创建原始字符串。

var s = r'In a raw string, not even \n gets special treatment.'; //s不会换行

字符串字面量是编译时常量,带有字符串插值的字符串定义,若干插值表达式引用的为编译时常量则其结果也是编译时常量。

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

布尔

布尔只有两个值true和false,都是编译时常量。

Dart里不能像JavaScript里有if (nonbooleanValue)或者assert (nonbooleanValue)。(现代语言都这样,防止莫名的错误)。

// 检查是否是空字符串
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);

列表

跟JavaScript里数组类似。

var list = [1, 2, 3];
Dart推断是List<int>类型。如果在这个列表里加入非整型对象,会引发错误。

列表也是从0开始的索引,最大索引为list.length - 1。

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

创建一个编译时常量的列表,要把const放在字面量前(表示的是这个列表是个常量,不能对其修改)。

var constantList = const [1, 2, 3];
// constantList[1] = 1; // 引发错误

Dart 2.3引入...和…?来简化插入多个值。

var list = [1, 2, 3];
var list2 = [0, ...list]; //...跟JavaScript里一样
assert(list2.length == 4);

var list;
var list2 = [0, ...?list]; //先判断一下是否是null
assert(list2.length == 1);

Dart 2.3还引入collection if和collection for(暂时不硬翻)。

var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];
var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

Set

Dart 2.2才引入Set字面量
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
//推断为Set<String>
//如果要创建空Set
var names = <String>{};
// Set<String> names = {}; // 这也能工作
// var names = {}; // 这是Map,不是Set

//增加元素
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

//用length获取长度
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

//编译时常量,用const修饰
final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // 会引发错误

Dart 2.3以后,…和...?也可以用于Set,用法跟List一样。

Map

//用字面量初始化
var gifts = { //推断为 Map<String, String>
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = { //推断为 Map<int, String>
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

//用构造函数初始化
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
Dart2里,new是可选的,所以可以用Map( )来替代new Map( )

在Map里新增值和获取值

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 新增键值对

var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

//用.length获取长度
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

// 也是用const声明编译时常量
final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

// constantMap[2] = 'Helium'; // 引发错误

Dart 2.3以后,...?也可以用于Map,用法跟List一样。

Runes

Dart里,runes是UTF-32的Unicode code point。

Unicode 为每一个字符、标点符号、表情符号等都定义了 一个唯一的数值。 由于 Dart 字符串是 UTF-16 code units 字符序列, 所以在字符串中表达 32-bit Unicode 值就需要 新的语法了。

通常用\uXXXX来表示一个Unicode code point,XXXX是一个四位十六进制值。比如♥就是\u2655。如果多于四位,就用{ }包含,比如😆就是\u{1f600}。(这些方法也很像JavaScript里es6新增的字符串方法)

字符串里有一些方法跟rune有关,比如codeUnitAt和codeUnit返回16位码。使用runes属性来获得字符串的rune。

//这个例子表现了rune 16位code point 32位code point之间的关系
main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}
// 输出
/* 
👏
[55357, 56399]
[128079]
♥  😅  😎  👻  🖖  👍
*/

Symbol

Symbol代表了Dart程序里的操作符或标志符。你可能从来都用不到symbol,但是该功能对于通过名字来引用标识符的情况下很有用,特别是混淆后的代码,标识符的名字被混淆了,但是symbol的名字不会改变。

Symbol字面量是编译时常量。

// 用#放在标志符前来获得symbol的字面量
#radix
#bar

发布于 2019-10-19

文章被以下专栏收录