A Tour of the Dart Language

一个基础的Dart程序

以下的代码使用了许多Dart最基础的特性:

  1. // Define a function.
  2. printInteger(int aNumber) {
  3. print('The number is $aNumber.'); // Print to console.
  4. }
  5. // This is where the app starts executing.
  6. main() {
  7. var number = 42; // Declare and initialize a variable.
  8. printInteger(number); // Call a function.
  9. }

以下是针对所有(或几乎所有)Dart apps都会使用到的东西:

// This is a comment.
一个单行注释。Dart也支持多行注释和文档注释。

int
表示类型。还有一些其他的内置类型,如String、List以及bool。

42
数字文字。数字文字是一种编译时常数。

print()
一个展示输出内容的便捷的方式。

$variableName (or ${expression})
字符串插值:在字符串文本中包含变量或表达式的字符串等效项。

main()
启动应用程序执行的特殊、必需的顶级函数。

var
一种定义不指定类型的变量的方法。

重要的概念

在学习DART语言时,请记住以下事实和概念:

  • 可以放在变量中的所有东西都是对象,每个对象都是类的实例。偶数、函数和NULL都是对象。所有对象都继承自Object类。
  • 虽然Dart是强类型的,但类型注释是可选的,因为Dart可以推断类型。在上面的代码中,数字被推断为int类型。如果要显式声明不需要任何类型,请使用特殊类型Dynamic。
  • Dart支持泛型类型,如List(整数列表)或List(任何类型的对象列表)。
  • Dart支持顶级函数(如main())以及绑定到类或对象的函数(分别为静态方法和实例方法)。您还可以在函数中创建函数(嵌套或本地函数)。
  • 类似地,Dart支持顶级变量,以及绑定到类或对象(静态和实例变量)的变量。实例变量有时称为字段或属性。
  • 与Java不同,Dart没有public、protected和private关键字。如果标识符以下划线(_)开头,则该标识符对其库是私有的。
  • 标识符可以字母或下划线(_)开头,后跟这些字符加数字的任何组合。
  • 需要清楚的界定好某条语句是一个表达式还是陈述式。
  • Dart工具可以报告两种类型的问题:警告和错误。警告只是表明您的代码可能无法工作,但它们并不妨碍程序的执行。错误可以是编译时错误,也可以是运行时错误。编译时错误根本阻止代码执行;运行时错误会导致在代码执行时引发异常。

关键字

下表列出了DART语言专门处理的单词。
keyword
上标1的单词是内置标识符。避免使用内置标识符作为标识符。如果您试图为类名或类型名使用内置标识符,则会发生编译时错误。

带有上标2的两个字是较新的、有限的保留字,它们与在DART 1.0版本之后添加的异步支持有关。您不能在任何用异步、异步或同步标记的函数体中使用async, await或 yield作为标识符。有关更多信息,请参见异步支持。

关键字表中的所有其他字都是保留字。不能使用保留字作为标识符。

变量

下面是创建变量并对其进行初始化的示例:

  1. var name = 'Bob';

变量存储引用。名为name的变量包含一个带有“Bob”值的字符串对象的引用。

name变量的类型推断为String,但您可以通过指定它来更改该类型。如果对象不限于单个类型,请按照设计准则指定对象或动态类型。

  1. dynamic name = 'Bob';

另一种选择是显式声明可能推断的类型:

  1. String name = 'Bob';

Note:本页遵循《编码风格指南》,对局部变量使用var而不是类型注释。

默认值

未初始化变量的初始值为null。即使是数值类型的变量,初始值也是null,因为数字就像Dart中的其他东西一样,也是对象。

  1. int lineCount;
  2. assert(lineCount == null);

在生产代码中 assert() 的调用会被忽略。在开发过程中,除非条件为真,否则 assert(condition) 。有关详细信息,请参见断言。

Final and const

如果您不希望更改变量,请使用Final或const来取代var,或者除此之外额外再加上一个类型声明。一个final变量只能被赋值一次。常量变量是编译时常数.(常量变量是隐式的final变量。)一个final的顶级变量或类变量在第一次使用时被初始化。

Note:实例变量可以是final,但不能是const。

下面是创建和设置一个final变量的示例:

  1. final name = 'Bob'; // Without a type annotation
  2. final String nickname = 'Bobby';

你无法更改一个final变量的值:

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

对希望成为编译时常量的变量使用const。如果const变量是class级别,则将其标记为static const。在声明变量时,将值设置为编译时常量,如数字或字符串文字、常量变量或常量算术运算的结果:

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

const关键字不仅仅用于声明常量变量。您还可以使用它来创建常量值,以及声明创建常量值的构造函数。任何变量都可以有一个常量值。

  1. var foo = const [];
  2. final bar = const [];
  3. const baz = []; // Equivalent to `const []`

您可以在const声明的初始化表达式中省略const,就像上面的Baz一样。有关详细信息,请参见不要重复使用const。您可以更改不是final、不是const的值,即使它之前有一个常量值:

  1. foo = [1, 2, 3]; // Was const []

无法更改常量变量的值:

  1. baz = [42]; // Error: Constant variables can't be assigned a value.

有关使用const创建常量值的详细信息,请参阅 Lists, Maps, 和 Classes。

内置类型

DART语言特别支持以下类型:

  • numbers
  • strings
  • booleans
  • lists (also known as arrays)
  • maps
  • runes (for expressing Unicode characters in a string)
  • symbols

可以使用文本初始化这些特殊类型的任何对象。例如, 'this is a string' 是一个字符串文本,而 true 是一个布尔文本。

因为Dart中的每个变量都指向一个对象—— 一个类的实例 —— 您通常可以使用构造函数来初始化变量。有些内置类型有自己的构造函数。例如,您可以使用 Map() 构造函数来创建映射。

数字

Dart Numbers 有两种: int
整数值不大于64位,具体取决于平台。在Dart虚拟机上, 取值范围为 -263~263-1。使用JavaScript Numbers编译为JavaScript的DART,允许值为-253~253-1。 double
64位(双精度)浮点数,符合IEEE 754标准。 intdouble都是num的子类型。num类型包括基本运算符,例如+、-、/和,您还可以在其中找到abs()cill()log()等方法。(像 >> 这样的位运算符是在int类中定义的。)如果num及其子类型没有您要寻找的内容,则dart:math库可能会包含。 Integers是没有小数点的数字。下面是一些定义整数文本的示例: Dart int x = 1; int hex = 0xDEADBEEF; 如果一个数字包含小数点,那么它就是double。下面是一些定义double文本的示例: Dart double y = 1.1; double exponents = 1.42e5; 下面是如何将字符串转换为数字的方法,反之亦然: Dart // 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'); int类型支持传统的位移(<<,>>),与(&)和或(|)运算符。例如: Dart assert((3 << 1) == 6); // 0011 << 1 == 0110 assert((3 >> 1) == 1); // 0011 >> 1 == 0001 assert((3 | 4) == 7); // 0011 | 0100 == 0111 数字是编译时的常量。许多算术表达式也是编译时的常量。它们的运算结果也是可以计算到数字的编译时常量。 ``` Dart const msPerSecond = 1000; const secondsUntilRetry = 5; const msUntilRetry = secondsUntilRetry msPerSecond; ```

字符串

DART字符串是UTF-16编码的单元序列。可以使用单引号或双引号创建字符串:

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

你可以通过使用${expression}将表达式的值嵌入字符串中。如果表达式是标识符,则可以省略{}。Dart可以调用对象的toString()方法获取与对象相对应的字符串。

  1. var s = 'string interpolation';
  2. assert('Dart has $s, which is very handy.' ==
  3. 'Dart has string interpolation, ' +
  4. 'which is very handy.');
  5. assert('That deserves all caps. ' +
  6. '${s.toUpperCase()} is very handy!' ==
  7. 'That deserves all caps. ' +
  8. 'STRING INTERPOLATION is very handy!');

Note:==操作符可以测试两个对象是否相等。如果两个字符串包含相同的代码单元序列,则它们是相等的。

你可以让字符串保持相邻或者使用+运算符来连接字符串:

  1. ar s1 = 'String '
  2. 'concatenation'
  3. " works even over line breaks.";
  4. assert(s1 ==
  5. 'String concatenation works even over '
  6. 'line breaks.');
  7. var s2 = 'The + operator ' + 'works, as well.';
  8. assert(s2 == 'The + operator works, as well.');

另一种创建多行字符串的方法:使用带有单引号或双引号的三元引号:

  1. var s1 = '''
  2. You can create
  3. multi-line strings like this one.
  4. ''';
  5. var s2 = """This is also a
  6. multi-line string.""";

你可以通过添加前缀r创建一个”原始”的字符串:

  1. var s = r'In a raw string, not even \n gets special treatment.'

如何在字符串中表示Unicode字符,请参考Runes获取详情。

字符串文本是编译时常量,只要任何插值表达式的值是null或数字、字符串或布尔值,它都是一个编译时常量。

  1. // These work in a const string.
  2. const aConstNum = 0;
  3. const aConstBool = true;
  4. const aConstString = 'a constant string';
  5. // These do NOT work in a const string.
  6. var aNum = 0;
  7. var aBool = true;
  8. var aString = 'a string';
  9. const aConstList = [1, 2, 3];
  10. const validConstString = '$aConstNum $aConstBool $aConstString';
  11. // const invalidConstString = '$aNum $aBool $aString $aConstList';

有关使用字符串的详细信息,请参阅字符串和正则表达式。

布尔

为了表示布尔值,DART有一个命名为bool的类型。只有两个对象具有bool类型:布尔文本true和false,它们都是编译时常量。

DART的类型安全性意味着您不能使用以下代码if(nonbooleanValue)assert (nonbooleanValue)。相反,需要显式地检查值,如下所示:

  1. // Check for an empty string.
  2. var fullName = '';
  3. assert(fullName.isEmpty);
  4. // Check for zero.
  5. var hitPoints = 0;
  6. assert(hitPoints <= 0);
  7. // Check for null.
  8. var unicorn;
  9. assert(unicorn == null);
  10. // Check for NaN.
  11. var iMeantToDoThis = 0 / 0;
  12. assert(iMeantToDoThis.isNaN);

列表

在几乎所有编程语言中,可能最常见的集合就是数组了,或者说是有序的对象组。在Dart中,数组是List对象,所以大多数人都叫它们列表。

Dart list文本与JavaScript数组文本。下面是一个简单的Dart list:

  1. var list = [1, 2, 3];

Note:分析器推断list具有类型List。如果尝试向此列表添加非整数对象,分析器分析或程序运行时将引发错误。有关更多信息,请阅读类型推断。

list使用零基索引,其中0是第一个元素的索引,list.length - 1是最后一个元素的索引。你可以得到一个列表的长度,并像在JavaScript中一样引用列表元素:

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

要创建一个编译时常量的列表,请在list之前添加const:

  1. var constantList = const [1, 2, 3];
  2. // constantList[1] = 1; // Uncommenting this causes an error.

list类型有许多方便的操作列表的方法。有关list的更多信息,请参阅Generics 和 Collections.。

映射

一般来说,映射是关联键和值的对象。键和值都可以是任何类型的对象。每个键只出现一次,但是您可以多次使用相同的值。Dart通过map文本和map类型提供对map的支持。

一下有一些简单的Dart map示例,通过map文本创建:

  1. var gifts = {
  2. // Key: Value
  3. 'first': 'partridge',
  4. 'second': 'turtledoves',
  5. 'fifth': 'golden rings'
  6. };
  7. var nobleGases = {
  8. 2: 'helium',
  9. 10: 'neon',
  10. 18: 'argon',
  11. };

Note:分析器推断,gifts拥有类型Map<String, String>noblegase拥有类型Map。如果您试图将错误类型的值添加到map中,那么解析或运行时就会出现错误。要了解更多信息,请阅读有关类型推断的内容。

您可以使用Map构造器创建相同的对象:

  1. var gifts = Map();
  2. gifts['first'] = 'partridge';
  3. gifts['second'] = 'turtledoves';
  4. gifts['fifth'] = 'golden rings';
  5. var nobleGases = Map();
  6. nobleGases[2] = 'helium';
  7. nobleGases[10] = 'neon';
  8. nobleGases[18] = 'argon';

注意:您可能期望看到new Map()而不是Map()。在Dart 2中,new关键字是可选的。有关详细信息,请参阅使用构造函数。

在现有的Map中添加一个新的键-值对,就像在JavaScript中一样:

  1. var gifts = {'first': 'partridge'};
  2. gifts['fourth'] = 'calling birds'; // Add a key-value pair

如果你查找一个不在map上的键,你会得到一个空值:

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

使用.length来获得map中键-值对的数量:

  1. var gifts = {'first': 'partridge'};
  2. gifts['fourth'] = 'calling birds';
  3. assert(gifts.length == 2);

要创建一个编译时常量的map,在map文本之前添加const:

  1. final constantMap = const {
  2. 2: 'helium',
  3. 10: 'neon',
  4. 18: 'argon',
  5. };
  6. // constantMap[2] = 'Helium'; // Uncommenting this causes an error.

有关map的更多信息,请参阅 Generics 和 Maps。

Runes

在Dart中,runes是UTF-32码点(Code Point)的字符串。

Unicode为世界上所有书写系统中使用的每个字母、数字和符号定义了唯一的数字值。由于Dart字符串是UTF-16代码单元的序列,所以在字符串中表示32位Unicode值需要特殊的语法。

通常表示Unicode编码点的方法是\uXXXX,其中XXXX是4位十六进制值。例如,字符(♥)的表示方式为\u2665。若要指定多于或少于4个十六进制数字,请将值置于花括号内。例如,笑的emoji字符(😆)是\u{1f600}

String类有几个属性可用于获取rune信息。codeUnitAtcodeUnit属性返回16位代码单元。使用runes属性获得runes的字符串。

下面的示例说明了runes、16位代码单元和32位码点之间的关系。

Note:使用list操作runes时要小心。根据特定的语言、字符集和操作,这种方法很容易崩溃。有关更多信息,请参见Stack Overflow上的如何在Dart中反转字符串