工欲善其事必先利其器,本篇我们就看下Dart语言的基本语法。
本文将从基本语法和变量开始到类的使用来向您介绍 Dart 编程语言的基本使用,这里假设你已经有使用其它语言进行编程的经验。
文章目录
重要的概念
-
所有变量引用的都是 对象,每个对象都是一个 类 的实例。数字、函数以及 null 都是对象。除去 null 以外(如果你开启了 空安全), 所有的类都继承于 Object 类。
-
尽管 Dart 是强类型语言,但是在声明变量时指定类型是可选的,因为 Dart 可以进行类型推断。
-
如果你开启了 空安全,变量在未声明为可空类型时不能为 null。你可以通过在类型后加上问号 (?) 将类型声明为可空。例如,int? 类型的变量可以是整型数字或 null。如果你 明确知道 一个表达式不会为空,但 Dart 不这么认为时,你可以在表达式后添加 ! 来断言表达式不为空(为空时将抛出异常)。例如:int x = nullableButNotNullInt!
-
如果你想要显式地声明允许任意类型,使用 Object?(如果你 开启了空安全)、 Object 或者 特殊类型 dynamic 将检查延迟到运行时进行。
-
Dart 支持泛型,比如 List(表示一组由 int 对象组成的列表)或 List(表示一组由任何类型对象组成的列表)。
-
Dart 支持顶级函数(例如 main 方法),同时还支持定义属于类或对象的函数(即 静态 和 实例方法)。你还可以在函数中定义函数(嵌套 或 局部函数)。
-
Dart 支持顶级 变量,以及定义属于类或对象的变量(静态和实例变量)。实例变量有时称之为域或属性。
-
Dart 没有类似于 Java 那样的 public、protected 和 private 成员访问限定符。如果一个标识符以下划线 (_) 开头则表示该标识符在库内是私有的。
-
标识符 可以以字母或者下划线 (_) 开头,其后可跟字符和数字的组合。
先从一段代码开始
// Define a function.
void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// This is where the app starts executing.
void main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}
下面是上述应用程序中使用到的代码片段,这些代码片段适用于所有(或几乎所有)的 Dart 应用:
// This is a comment.
// 注释。
以双斜杠开头的一行语句称为单行注释。Dart 同样支持也支持/**/注释。
void
以 void 声明的函数返回类型,并不会返回值。
int
另一种数据类型,表示一个整型数字。 Dart 中一些其他的内置类型包括 String、List 和 bool。
42
表示一个数字字面量。数字字面量是一种编译时常量。
print()
一种便利的将信息输出显示的方式。
‘…’ (或 “…”)
表示字符串。
$variableName (或 ${expression})
表示字符串插值:字符串字面量中包含的变量或表达式。
main()
顾名思义,dart语言程序主入口,Dart 应用程序总是会从该函数开始执行。
var
用于定义变量,通过这种方式定义变量不需要指定变量类型。这类变量的类型 (int) 由它的初始值决定 (42)。
变量
下面的示例代码将创建一个变量并将其初始化:
var name = 'Bob';
变量仅存储对象的引用。这里名为 name 的变量存储了一个 String 类型对象的引用,“Bob” 则是该对象的值。
name 变量的类型被推断为 String,但是你可以为其指定类型。如果一个对象的引用不局限于单一的类型,可以将其指定为 Object(或 dynamic)类型。
Object name = 'Bob';
除此之外你也可以指定类型:
String name = 'Bob';
本文遵循 Dart风格建议指南 中的建议,通过 var 声明局部变量而非使用指定的类型。
默认值
在 Dart 中,未初始化以及可空类型的变量拥有一个默认的初始值 null。(如果你未迁移至 空安全,所有变量都为可空类型。)即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。
int? lineCount;
assert(lineCount == null);
assert() 的调用将会在生产环境的代码中被忽略掉。在开发过程中,assert(condition) 将会在 条件判断 为 false 时抛出一个异常。
若你启用了空安全,你必须在使用变量前初始化它的值。
int lineCount = 0;
你并不需要在声明变量时初始化,只需在第一次用到这个变量前初始化即可。例如,下面的代码是正确的,因为 Dart 可以在 lineCount 被传递到 print() 时检测它是否为空:
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
print(lineCount);
顶级变量以及类变量是延迟初始化的,即检查变量的初始化会在它第一次被使用的时候完成。
延迟初始化变量
Dart 2.12 新增了 late 修饰符,这个修饰符可以在以下情况中使用:
- 声明一个非空变量,但不在声明时初始化。
- 延迟初始化一个变量。
通常 Dart 的语义分析会在一个已声明为非空的变量被使用前检查它是否已经被赋值,但有时这个分析会失败。例如:在检查顶级变量和实例变量时,分析通常无法判断它们是否已经被初始化,因此不会进行分析。
如果你确定这个变量在使用前就已经被声明,但 Dart 判断失误的话,你可以在声明变量的时候使用 late 修饰来解决这个问题。
late String description;
void main() {
description = 'Feijoada!';
print(description);
}
若 late 标记的变量在使用前没有初始化,在变量被使用时会抛出运行时异常。
如果一个 late 修饰的变量在声明时就指定了初始化方法,那么它实际的初始化过程会发生在第一次被使用的时候。这样的延迟初始化在以下场景中会带来便利:
- Dart 认为这个变量可能在后文中没被使用,而且初始化时将产生较大的代价。
- 你正在初始化一个实例变量,它的初始化方法需要调用 this。
在下面这个例子中,如果 temperature 变量从未被使用的话,那么 readThermometer() 将永远不会被调用:
// This is the program's only call to readThermometer().
late String temperature = readThermometer(); // Lazily initialized.
Final 和 Const
如果你不想更改一个变量,可以使用关键字 final 或者 const 修饰变量,这两个关键字可以替代 var 关键字或者加在一个具体的类型前。一个 final 变量只可以被赋值一次;一个 const 变量是一个编译时常量 (const 变量同时也是 final 的)。
实例变量 可以是 final 的但不可以是 const
下面的示例中我们创建并设置两个 final 变量:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
你不能修改一个 final 变量的值。
使用关键字 const 修饰变量表示该变量为 编译时常量。如果使用 const 修饰类中的变量,则必须加上 static 关键字,即 static const(译者注:顺序不能颠倒)。在声明 const 变量时可以直接为其赋值,也可以使用其它的 const 变量为其赋值:
const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere
const 关键字不仅仅可以用来定义常量,还可以用来创建 常量值,该常量值可以赋予给任何变量。你也可以将构造函数声明为 const 的,这种类型的构造函数创建的对象是不可改变的。
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`
如果使用初始化表达式为常量赋值可以省略掉关键字 const,比如上面的常量 baz 的赋值就省略掉了 const。详情请查阅 不要冗余地使用 const。
没有使用 final 或 const 修饰的变量的值是可以被更改的,即使这些变量之前引用过 const 的值。
foo = [1, 2, 3]; // Was const []
你可以在常量中使用 类型检查和强制类型转换 (is 和 as)、 集合中的 if 以及 展开操作符 (… 和 …?):
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {
if (i is int) i: 'int'}; // Use is and collection if.
const set = {
if (list is List<int>) ...list}; // ...and a spread.
内置类型
Dart 语言支持下列内容:
- Numbers (int, double)
- Strings (String)
- Booleans (bool)
- Lists (也被称为arrays)
- Sets (Set)
- Maps (Map)
- Runes (常用于在 Characters API 中进行字符替换)
- Symbols (Symbol)
- The value null (Null)
使用字面量来创建对象也受到支持。例如 ‘This is a string’ 是一个字符串字面量,true 是一个布尔字面量。
由于 Dart 中每个变量引用都指向一个对象(一个 类 的实例),通常也可以使用 构造器 来初始化变量。一些内置的类型有它们自己的构造器。例如你可以使用 Map() 来创建一个 map 对象。
Numbers
Dart 支持两种 Number 类型:
int
整数值;长度不超过 64 位,具体取值范围 依赖于不同的平台。在 DartVM 上其取值位于 -263 至 263 - 1 之间。在 Web 上,整型数值代表着 JavaScript 的数字(64 位无小数浮点型),其允许的取值范围在 -253 至 253 - 1 之间。
double
64 位的双精度浮点数字,且符合 IEEE 754 标准。
int 和 double 都是 num 的子类。 num 中定义了一些基本的运算符比如 +、-、*、/ 等,还定义了 abs()、ceil() 和 floor() 等方法(位运算符,比如 >> 定义在 int 中)。如果 num 及其子类不满足你的要求,可以查看 dart:math 库中的 API。
整数是不带小数点的数字,下面是一些定义整数字面量的例子:
var x = 1;
var hex = 0xDEADBEEF;
如果一个数字包含了小数点,那么它就是浮点型的。下面是一些定义浮点数字面量的例子:
var y = 1.1;
var exponents = 1.42e5;
整型字面量将会在必要的时候自动转换成浮点数字面量:
double z = 1; // Equivalent to double z = 1.0.
版本提示:
在 Dart 2.1 之前,在浮点数上下文中使用整数字面量是错误的。
下面是字符串和数字之间转换的方式:
// 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 | 4) == 7); // 0011 | 0100 == 0111
assert((3 & 4) == 0); // 0011 & 0100 == 0000
数字字面量为编译时常量。很多算术表达式只要其操作数是常量,则表达式结果也是编译时常量。
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;
字符串
Dart 字符串(String 对象)包含了 UTF-16 编码的字符序列。可以使用单引号或者双引号来创建字符串:
var s1 = '使用单引号创建字符串字面量。';
var s2 = "双引号也可以用于创建字符串字面量。";
var s3 = '使用单引号创建字符串时可以使用斜杠来转义那些与单引号冲突的字符串:\'。';
var s4 = "而在双引号中则不需要使用转义与单引号冲突的字符串:'";
在字符串中,请以 ${表达式} 的形式使用表达式,如果表达式是一个标识符,可以省略掉 {}。如果表达式的结果为一个对象,则 Dart 会调用该对象的 toString 方法来获取一个字符串。
var s = '字符串插值';
assert('Dart 有$s,使用起来非常方便。' == 'Dart 有字符串插值,使用起来非常方便。');
assert('使用${
s.substring(3,5)}表达式也非常方便' == '使用插值表达式也非常方便。');
备注:
== 运算符负责判断两个对象是否等同,比如,如果两个字符串包含一样的字符编码序列,则表示他们是等同的。
你可以使用 + 运算符或并列放置多个字符串来连接字符串:
var s1 = '可以拼接'
'字符串'
"即便它们不在同一行。";
assert(s1 == '可以拼接字符串即便它们不在同一行。');
var s2 = '使用加号

本文介绍了Dart语言的基本语法,包括变量(默认值、延迟初始化、Final和Const)、内置类型(如Numbers、Strings、Booleans、Lists、Sets、Maps),以及函数(参数、返回值、构造函数)。此外,还提到了Dart中的常量、集合操作和类型系统。
最低0.47元/天 解锁文章
1463





