简介

Dart语言诞生于2011年10月10日,由谷歌主导开发的开源语言,Dart是一种“结构化的Web编程”语言,可以在所有现代浏览器和环境中提供高性能。Dart语言可用于Web、服务器、移动应用和物联网等领域的开发。

Dart语言目前最新版本是2.17.6,目前可用于全平台的开发,注意Dart也是一门面向对象的编程语言。

Flutter和Dart有什么关系呢?早期的Flutter团队在评估了十多种语言之后才选择了Dart,因为它符合构建用户界面的方式。

Flutter团队看重的Dart语言部分特性

(1)Dart是AOT(Ahead Of Time)编译的,编译成快速、可预测的本地代码,使得Flutter几乎都可以使用Dart编写。这不仅使得Flutter变得更快,而且几乎所有的组件(包括所有的小组件)都可以定制。
(2)Dart也可以JIT(Just In Time)编译,开发周期非常短,工作流颠覆常规(包括Flutter流行的亚秒级有状态热重载)。
(3)Dart可以更轻松的创建以60fps运行的流畅动画和转场。Dart可以在没有锁的情况下进行对象分配和垃圾回收。就像JavaScript一样,Dart避免了抢占式调度和共享内存(因此也不需要锁)。由于Flutter应用程序被编译为本地代码,因此不需要在领域之间建立缓慢的桥梁(如JavaScript到本地代码)。它的启动速度也快很多。
(4)Dart使得Flutter不需要单独的声明式布局语言(如JSX或者XML)或者单独的可视化界面构建器,因为Dart的声明式编程布局易于阅读和可视化。所有的布局使用一种语言,聚齐在一处,Flutter很容易提供高级工具,使得布局更加简单。
(5)开发人员发现Dart语言特别容易学习,因为它具有静态和动态语言用户都熟悉的特性。
(6)以上这些功能并非都是Dart语言独有的,但是Dart将这些功能组合的恰到好处,使得Dart在实现Flutter方面独一无二。因此,没有Dart语言,很难想象Flutter是否能像现在这样强大。

当开发者想创建移动APP、Web APP、Command-Line应用时,都可以使用Dart语言。

Dart语言重要概念

(1)所有的东西都是对象,无论是变量、数字、函数等都是对象。所有的对象都是类的实例。所有对象都继承内置的Object类。这一点有点类似于Java语言中的“一切皆对象”。
(2)在程序中指定数据类型使得程序能够合理地分配内存空间,并帮助编译器进行语法检查。但是,指定类型并不是必须的,Dart语言是弱数据类型。
(3)Dart代码可以在运行前解析,指定数据类型和编译时的常量可以提高运行速度。
(4)Dart程序有统一的程序入口:main(),这一点与Java、C/C++语言相似。
(5)Dart语言没有public、protected和private等概念,私有特性通过变量或者函数加上下划线来表示。
(6)Dart的工具可以检查出警告信息(warning)和错误信息(errors)。警告信息只是表明代码可能不工作,但是不会妨碍程序的运行。错误信息可能是编译时的错误,也可能是运行时的错误,编译时的错误将阻止程序运行,运行时的错误将会以异常(exception)的方式呈现。
(7)Dart支持anync/await异步处理。

Dart语言中的关键字

Dart语言中存在56个关键字,分别如下所示:abstract、do、import、super、as、dynamic、in、switch、assert、else、interface、sync*、、enum、implements、is、this、async*、export、library、throw、await、external、mixin、true、break、extends、new、try、case、factory、null、typedef、catch、false、operator、var、class、final、part、void、const、finally、rethrow、while、continue、for、return、with、covariant、get、set、yield*、default、if、static、deferred。

Dart语言常用库

Dart语言常用库如下表示所示:
|包名|描述|
|:—-:|:—-:|
|dart:async|异步编程支持,提供Future和Stream类|
|dart:collection|对dart:core提供更多的集合支持|
|dart:convert|不同类型(JSON,UTF-8)间的字符编码、解码支持|
|dart:core|Dart语言内建的类型、对象以及Dart语言的核心功能|
|dart:html|网页开发用到的库|
|dart:io|文件读写I/O相关操作的库|
|dart:math|数字常量以及函数,提供随机数算法|
|dart:svg|事件和动画的矢量图像支持|

在上述常用的库中,以下三个开发库使用频率非常高:
(1)dart:core,这是Dart语言的核心库,包括strings、numbers、collections、errors、dates、URIs等。
(2)dart:html,网页开发中DOM相关的一些库。
(3)dart:io,I/O命令行使用的I/O库。
请注意,dart:core是Dart语言初始化已经包含的库,其他的任何库在使用前都需要通过import关键字来进行导入。举个例子,要使用dart:html库,可以使用如下命令进行导入:

1
import 'dart:html';

当然,使用官方提供的pub工具可以安装丰富的第三方库,第三方库地址为 https://pub.dev/

Dart环境搭建

Dart SDK安装

在Windows系统上,可以使用choco install dart-sdk命令来进行安装,具体的可以点击 这里 进行安装:

当然了,开发者还可以点击 这里 下载Windows系统的版本:

建议选择稳定版本进行下载,然后选择一个合适的安装目录进行傻瓜式的安装。如果出现网络安装失败的情况,可以选择retry或者更换下载地址为 这里 ,开发者自己手动来下载SDK:

点击进入后,选择合适的操作系统及Dart版本:

之后下载zip压缩包直接解压,接着开始设置环境变量。
(1)设置系统变量DART_SDK,值就是刚才解压的zip的路径,注意只需填写到dart-sdk这一目录即可:

(2)设置系统变量PATH,值就是刚才解压的zip的路径,注意需要填写到dart-sdk/bin这一目录:

(3)检查Dart是否安装成功:

1
2
C:\Users\Kenbings>dart --version
Dart SDK version: 2.17.6 (stable) (Tue Jul 12 12:54:37 2022 +0200) on "windows_x64"

Dart IDE安装

这里笔者选择了Android Studio为开发工具,当然IDEA之类的工具也是可以的。

Dart插件安装

这里笔者以Android Studio为例来介绍Dart插件的安装。在Settings–>Plugins里面选择Dart插件:

接着选择Flutter插件:

最后再来安装Material Theme UI插件:

Dart语言入门

依次按照如下图示创建一个Dart项目:

之后新建一个名为hello_world.dart文件,里面的代码如下所示:

1
2
3
4
5
6
7
/**
* main方法是程序入口
* print方法可以在控制台输出内容
*/
void main(){
print("hello,world");
}

之后直接运行该main方法,可以看到控制台输出“hello,world”字样。

Dart中的变量与常量

在Dart中声明变量使用var关键字,注意它可被赋予不同类型的值。举个例子,如下所示:

1
var name = "张三";

在Dart语言中一切皆对象,所以如果没有将变量初始化,那么它的默认值就是null。举个例子,如下声明了变量a,但是没有给它赋值,那么默认值就是null:

1
2
3
4
void main(){
var a;
print(a); //null
}

此时我们可以给它赋值一个数字类型:

1
2
3
4
5
6
void main(){
var a;
print(a); //null
a = 66;
print(a); //66
}

接着我们再将这个a变量赋值为一个字符串类型:

1
2
3
4
5
6
7
8
void main(){
var a;
print(a); //null
a = 66;
print(a); //66
a = "hello,dart";
print(a); //hello,dart
}

当然了,我们也可以在声明变量的时候立即给它初始化:

1
2
3
4
void main(){
var b = "hello,dart";
print(b); //hello,dart
}

常量及固定值在开发中很常见,如星期一到星期日,一年的12个月,这些数据都可以定义为常量形式。如果定义的变量不会发生变化,可以使用final或者const来声明。注意const是一个编译时常量,而final的值只能被设定一次,即使用final声明一个只能赋值一次的变量。

举个例子,如下声明了一个final常量username,如果用户对此变量重新赋值,那么将会引发异常:

1
2
fianl username = "张三";
// username = "李四"; //会引发一个错误

同样使用const定义的常量也不能进行二次赋值,否则会引发错误。可以看到使用final和const定义的常量都是不能进行二次赋值的,那么这两个有什么区别呢?这个在后面就知道了。

通过对const类型做四则运算将自动得到一个const类型的值。举个例子,下面的代码会计算圆的面积,并得到一个常量:

1
2
3
4
5
void main(){
const pi = 3.1415926;
const area = pi * 100 * 100;
print(area);
}

当然了,也可以通过const来创建常量的值,也就是说const[]本身就是构造函数。举个例子,如下所示:

1
2
final stars = const [];
const buttons = const [];

Dart中的基本数据类型

Dart语言常用的基本数据类型有:Number(数值型)、String(字符串)、Boolean(布尔型)、List(数组)和Map(键值对)。

Number(数值型)

Number(数值型)包括以下两类:
(1)int(整型):取值范围:-2^53 ~ 2^53。
(2)double(浮点型):64位长度的浮点型数据,即双精度浮点型。

注意int和double类型都是num类型的子类。int类型不能包含小数点。

num类型包括的操作有:+-*/%(取余)、~/(取整)以及位移操作>>

num类型包括的常用方法有:abs(绝对值)、ceil(不小于它的最小整数)、round(四舍五入)和floor(不大于它的最大整数)、toInt(浮点型转整型)和toDouble(整型转浮点型)。

num类型包括的常用属性有:isNaN(是否为非数字)、isEven(是否为偶数)和isOdd(是否为奇数)。

来看几个实际的例子:

1
2
3
4
5
6
7
8
9
10
11
12
void main(){
num a = 10;
a = 12.5;
print(a); //12.5

int b = 10;
//b = 16.6; //引发错误

double c = 12.5;
c = 60; //可以自动将整型转为浮点型
print(c); //60.0
}

String(字符串)

String类型就是字符串类型,在开发中大量使用。(1)使用单引号或者双引号创建字符串。(2)使用三个引号或者双引号创建多行字符串。(3)使用r创建原始raw字符串。

举个例子,下面分别演示了上述三种创建字符串的方式:

1
2
3
4
5
6
7
8
9
10
11
12
void main(){
String str1 = "hello";
String str2 = '''hello,dart''';
print(str1); //hello
print(str2); //hello,dart

String str3 = "hello \n dart";
print(str3); //hello换行 dart

String str4 = r"hello \n dart";
print(str4); //hello \n dart
}

【字符串操作】
(1)运算符:+*==(判断字符串内容)、[](取字符串中的字符,下标从0开始)。下面的例子分别介绍了上述四种运算符的使用:

1
2
3
4
5
6
7
8
9
void main(){
String str1 = "I am come from";
String str2 = "I am 25 years old";
print(str1 + " beijing"); //I am come from beijing
print(str1 * 3); //I am come fromI am come fromI am come from
print(str1 == str2); //false
print(str1[0]); //I
print(str1[2]); //a
}

(2)插值表达式${expression}。举个例子,如下所示:

1
2
3
4
5
6
void main(){
int a = 1;
int b = 2;
print("a + b = ${a+b}"); //a + b = 3
print("a = $a"); //a = 1
}

(3)常用属性:length、isEmpty和isNotEmpty。举个例子,如下所示:

1
2
3
4
5
6
void main(){
String str1 = "I am come from beijing";
print(str1.length); //22
print(str1.isEmpty); //false
print(str1.isNotEmpty); //true
}

(4)常用方法:contains()、subString()、startsWith()、endsWith()、indexOf()、lastIndexOf()、toLowerCase()、toUpperCase()、trim()、trimLeft()、trimRight()、split()、replaceXXX()等。举个例子,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void main(){
String str1 = "I am come from beijing";
print(str1.contains("I")); //true
print(str1.substring(0,3)); //I a(左闭右开区间)
print(str1.startsWith("a")); //false
print(str1.endsWith("g")); //true
print(str1.indexOf("a")); //2
print(str1.lastIndexOf("m")); //13
print(str1.toLowerCase()); //i am come from beijing
print(str1.toUpperCase()); //I AM COME FROM BEIJING
print(str1.trim()); //I am come from beijing
var list = str1.split(" ");
print(list); //[I, am, come, from, beijing]
print(list.length); //5

print(str1.replaceAll("I", "you")); //you am come from beijing
}

Boolean(布尔型)

Dart是强Boolean类型检查,只有bool类型的值是true才会被认为是true。有的语言里0是false,大于0的是true,但是在Dart语言中不是,值必须为true或者false。举个例子,如下所示:

1
2
3
4
5
6
7
8
9
void main(){
bool flag = true;
print(flag); //true

var sex = "男";
if(sex){ //会抛异常
print("你的性别是: "+sex);
}
}

可以看到后面的代码无法通过编译,原因在于sex变量是一个字符串,不能使用条件判断语句,必须使用Boolean类型才可以。

List(数组)

Dart里的List对象类似于JavaScript中的数组Array对象。定义List的例子如下所示:

1
2
3
4
5
6
7
8
9
10
11
void main(){
var list = [1,2,"hello",true];
print(list); //[1, 2, hello, true]

print(list.length); //4
print(list[0]); //1
print(list[list.length-1]); //true

list[1] = 66;
print(list); //[1, 66, hello, true]
}

List对象的第一个元素的索引是0,最后一个元素的索引是list.length-1

创建不可变的list可使用如下方式,所谓的list指的是其内容无法进行修改:

1
2
3
4
void main(){
var list = const [1,2,3];
list[1] = 66; //Unsupported operation: Cannot modify an unmodifiable list
}

当然了,也可以通过构造来创建,举个例子,如下所示:

1
var list = new List();  //这种方式不建议使用,因为它可能产生不安全问题

【常用操作】
(1)[],可用于获取或者更改元素的值;
(2)length,用于获取list的长度;
(3)add(),用于往数组末尾添加元素;
(4)insert(),用于往数组指定位置插入元素;
(5)remove(),用于删除数组中的末尾元素;
(6)clear(),用于清空数组中的所有元素;
(7)indexOf(),用于查找某个元素第一次在数组中出现的位置;
(8)lastIndexOf(),用于查找某个元素最后一次在数组中出现的位置;
(9)sort(),对数组进行排序;
(10)sublist(),获取数组的子数组;
(11)shuffle(),随机打乱这个数组中的元素。;
(12)asMap(),将数组转换为一个map;
(13)forEach(),遍历数组的元素;
举个例子,下面对于上述list操作进行了演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void main(){
var list = ["hello","dart"];
print(list.length); //2
list.add("world");
print(list); //[hello, dart, world]

list.insert(1,"java");
print(list); //[hello, java, dart, world]

list.remove("java");
print(list); //[hello, dart, world]

// list.clear();
// print(list); //[]

print(list.indexOf("dart")); //1
print(list.indexOf("dart1")); //-1

list.sort();
print(list); //[dart, hello, world]

print(list.sublist(1)); //[hello, world] 左闭右闭区间

list.shuffle();
print(list); //[dart, hello, world]

list.forEach(print);
//dart
//hello
//world
}

Map(键值对)

Map类型将key和value关联在一起,也就是键值对,注意key的值必须是唯一的。

创建Map可使用如下方式:

1
2
3
4
void main(){
var language = {"first": "Dart","second": "Java"};
print(language); //{first: Dart, second: Java}
}

也可以使用如下方式创建一个不可变的Map:

1
2
3
4
void main(){
var language = const {"first": "Dart","second": "Java"};
print(language); //{first: Dart, second: Java}
}

还可以通过对象构造来创建Map:

1
2
3
4
5
6
void main(){
var language = new Map();
language["first"] = "Dart";
language["second"] = "Java";
print(language); //{first: Dart, second: Java}
}

下面通过一个例子来演示Map的创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main(){
var map1 = {"first": "Dart", 1:true, true: "6"};
print(map1); //{first: Dart, 1: true, true: 6}

print(map1["first"]); //Dart
print(map1[true]); //6

map1[true] = "8"; //注意修改map的值只能通过元素的key来修改
print(map1); //{first: Dart, 1: false, true: 8}

var map2 = const {1: "Dart", 2: "Java"};
//map2[2] = "Python"; //Unsupported operation: Cannot modify unmodifiable map

var map3 = new Map();
}

【常用操作】
(1)[],可用于获取或者更改元素的值;
(2)length,用于获取map中键值对的个数;
(3)isEmpty(),判断map是否为空;
(4)isNotEmpty(),判断map是否不为空;
(5)keys,用于获取map的所有key;
(6)values,用于获取map的所有value;
(7)containsKey(),用于判断map中是否包含某个key;
(8)containsValue(),用于判断map中是否包含某个value;
(9)remove,用于删除map的某个键值对;
(10)forEach,用于遍历map中的键值对。
举个例子,下面对于上述map操作进行了演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void main(){
var map = {"first": "Dart","second": "Java","third":"Python"};
print(map.length); //3
print(map.isEmpty); //false
print(map.isNotEmpty); //true

print(map.keys); //(first, second, third)
print(map.values); //(Dart, Java, Python)

print(map.containsKey("first")); //true
print(map.containsValue("Dart")); //true
print(map.containsValue("C")); //false

map.remove("third");
print(map); //{first: Dart, second: Java}

map.forEach((key, value) { print("key is "+key+ ",value is "+ value);});
//key is first,value is Dart
//key is second,value is Java

map.forEach(f);
//key=first,value=Dart
//key=second,value=Java

var list = ["1","2","3"];
print(list.asMap()); //{0: 1, 1: 2, 2: 3} 可以看到数组转成map时,默认key就是整型,从0开始,value就是数组的各个元素
}

void f(key,value){
print("key=$key,value=$value");
}

dynamic

其实在前面我们使用var关键字声明变量的时候,这个变量的类型就是dynamic,因此我们完全可以使用dynamic来声明一个可变类型的变量。dynamic更多时候则是用在泛型上:

1
2
3
4
5
6
7
8
9
10
11
12
void main(){
var a;
a = 12;
a = "Dart";
//这个a其实是一个dynamic类型

dynamic b = 20;
b = "JavaScript";

//这个dynamic可用在泛型上
var list = <dynamic>[];
}

Dart中的运算符

运算符通常也被称为操作符,Dart支持各种类型的运算符,并且其中的一些操作符还能进行重载。完整的操作符如下表所示:
|描述 |运算符|
|:—-:|:—-:|
|一元后缀 | expr++expr--()[]|
|一元前缀 | -expr!expr~expr++expr--expr|
|乘法类型 | */%~/|
|加法类型 | +-|
|移动位运算 | <<>>|
|与位运算 | &|
|异或位运算 | ^|
|或位运算 |竖线|
|关系和类型测试 | >=<=><asisis!|
|等式 | ==!=|
|逻辑与 | &&|
|逻辑或 | 双竖线|
|条件 | expr1? expr2:expr3|
|级联 | ..|
|赋值 |=*=/~/=%=+=-=<<=>>=&=^=竖线=??=|

注意上表中操作符的优先级是由上到下逐个减小,上面行内的操作符优先级高于下面行内的操作符。举个例子,“乘法类型”中的操作符%的优先级高于“等价“操作符==,而==的操作符的优先级又比“逻辑与”操作符&&要高。注意使用运算符时的顺序,方法如下所示:

1
2
3
4
//1、使用括号来提高可读性
if((n%i==0) && (d % i==0))
//2、难以阅读,但是和上面是等价的
if(n%i==0 && d % i==0)

对于二元运算符,其左边的操作数将会决定使用的操作符的种类。举个例子,当使用一个Vector对象以及一个Point对象时,aVector+aPoint使用的+是由Vector定义的。

算术运算符

Dart支持的常用算术运算符如下表所示:
|操作符 |含义|
|:—-:|:—-:|
|+ | 加|
|-| 减|
|-expr | 一元减号,即使后面表达式的值反过来|

  • | 乘|
    |/ | 除|
    |~/ | 取整|
    |%| 取余|

举个例子,如下所示:

1
2
3
4
5
6
7
8
void main(){
assert(3+6 == 9);
assert(3-6 == -3);
assert(3*6 == 18);
assert(7/2 == 3.5); //结果是浮点型
assert(5 ~/2 ==2); //结果是整型
assert(5 %2 == 1); //求余数
}

Dart还支持前缀和后缀递增和递减运算符,如下表所示:
|操作符 |含义|
|:—-:|:—-:|
|++var| var = var+1表达式的值为var+1|
|var++| var = var+1表达式的值为var|
|–var| var = var-1表达式的值为var-1|
|var–| var = var-1表达式的值为var|

举个例子,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void main(){
var a,b;
a = 0;
b = ++a; //在b获得其值之前自增a
print(a); //1
print(b); //1

a = 0;
b = a++; //在b获得值后自增a
print(a); //1
print(b); //0

a = 0;
b = --a; //在b获得其值之前自减a
print(a); //-1
print(b); //-1

a = 0;
b = a--; //在b获得值后自减a
print(a); //-1
print(b); //0
}

关系运算符

等式和关系运算符的含义如下表所示:
|操作符 |含义|
|:—-:|:—-:|
|==|等于|
|!=|不等于|
|>|大于|
|<|小于|
|>=|大于等于|
|<=|小于等于|

请注意,如果需要判断两个对象的内容是否相等,请使用==运算符。

举个例子,如下所示:

1
2
3
4
5
6
7
8
void main(){
assert(2 ==2);
assert(2 !=3);
assert(3 >2);
assert(2 <3);
assert(2 >=2);
assert(2 <=3);
}

类型测试操作符

asisis!操作符在运行时用于检查类型非常方便,含义如下所示:
|操作符 |含义|
|:—-:|:—-:|
|as|类型转换|
|is|当对象是相应类型时返回true|
|is!|当对象不是相应类型时返回true|

如果obj实现了T所定义的接口,那么obj is T将返回true。使用as操作符可以将一个对象转换为指定类型,前提是能够转换。在转换之前,使用is判断更为稳妥。

举个例子,如下所示:

1
2
3
4
if(user is User){
//类型检测
user.name = "flutter";
}

如果能确定user是User的实例,那么可以通过as操作符直接简化代码:

1
(user as User).name = "flutter";

请注意,上面两段代码并不相等。如果user的值是null或者不是一个User对象,那么第一段代码不会做任何事情,而第二段代码会抛异常。

赋值操作符

可以使用=运算符赋值。如果开发者想仅在变量为null时赋值,可以使用??=运算符。举个例子,如下所示:

1
2
3
4
//赋值给a
a = value;
//如果b为空则将value赋值给它,否则b的值保持不变
b ??= value;

诸如+=之类的复合赋值运算符将操作与赋值相结合。以下是复合赋值运算符的工作方式:
|复合赋值|等式表达式|
|:—-:|:—-:|
|a op b|a = a op b|
|a += b|a = a +b|
|a -= b|a = a -b|

逻辑运算符

可以使用逻辑运算符反转或者组合布尔表达式,逻辑运算符如下所示:
|操作符|含义|
|:—-:|:—-:|
|!expr|反转以下表达式(将false更改为true,反之将true更改为false)|
|双竖线|逻辑或|
|&&|逻辑与|

举个例子,如下所示:

1
2
3
if( !expr && (test == 2 || test==6)){
//TODO
}

条件表达式

Dart中有两个运算符,可用来简明地评估可能需要if-else语句的表达式。下面所示的代码就是一种条件表达式,也可以称为三元表达式。如果条件为真,则返回expr1,否则返回expr2:

1
condition? expr1:expr2;

第二种方式则如下所示,如果expr1为非空,则返回其值;否则计算并返回expr2的值:

1
expr1?? expr2

注意这个expr1必须是一个允许空的类型,如果使用字符串,而字符串本身就是非空类型,此时代码会抛出异常。

级联操作

级联操作使用两个点..来表示,可对同一对象执行一系列操作。类似于JavaScript中的Promise的then处理。级联操作的主要目的是为了简化代码。举个例子,如下所示:

1
2
3
4
querySelector('#btnOk')  //获取一个id为btnOk的按钮对象
..text = '确定' //使用它的成员
..classes.add('ButtonOKStyle')
..onClick.listen((e) => window.alert('确定'));

可以看到第一个方法调用querySelector,返回一个按钮对象,之后再设置它的文本为“确定”,接着再给这个按钮添加一个样式“ButtonOKStyle”,最后监听单机事件,事件弹出一个显示“确定”的警告。其实这个例子就相当于下面的操作:

1
2
3
4
var button = querySelector('#btnOk');
button.text = '确定';
button.classes.add('ButtonOKStyle');
button.onClick.listen((e) => window.alert('确定'));

严格意义来说,级联的双点符号并不是运算符,而是Dart语法的一部分。

Dart中的流程控制语句

Dart中的流程控制语句主要有如下7个:if和else、for(循环)、while和do-while(循环)、break和continue、switch和case、assert(断言)、try-catch和throw。

if和else

Dart支持if及else的多种组合,如下面的例子所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void main(){
int score = 99;
if(score > 90){
print("优秀");
}else if(score > 80){
print("良好");
}else if(score > 70){
print("中等");
}else if(score > 60){
print("及格");
}else{
print("不及格");
}
}

上面的代码将输出“优秀”,条件语句执行到第一条判断就停止了。

for(循环)

【普通的for(循环)】下面的例子说明for循环,首先定义了一个字符串“hello,dart”,然后使用for循环向message变量中写入5个同样的字符”!”,如下所示:

1
2
3
4
5
6
7
void main(){
var message = new StringBuffer("hello,dart");
for(var i = 0;i<5;i++){
message.write("!");
}
print(message); //hello,dart!!!!!
}

注意上面的值是在字符串尾部进行添加的。除了常规的for循环外,针对可以序列化的操作数,还可以使用for..in循环。
【for..in循环】如果开发者不关心操作数的当前下标时,此时使用for..in循环是非常方便的。举个例子,如下所示:

1
2
3
4
5
6
void main(){
var arr = [1,3,5,7,9,11];
for(var v in arr){
print(v); // 1 3 5 7 9 11
}
}

while和do-while(循环)

【while】下面的例子说明while循环,其中定义了一个变量temp。temp会在循环体内自动加1,当条件(temp <5)不满足时,就会退出循环,如下所示:

1
2
3
4
5
6
7
void main(){
var temp = 0;
while(temp <5){
print("这是一个while循环: "+temp.toString());
temp++;
}
}

程序执行结果如下所示:

1
2
3
4
5
这是一个while循环: 0
这是一个while循环: 1
这是一个while循环: 2
这是一个while循环: 3
这是一个while循环: 4

【do-while】当然了,上述例子也可以使用do-while语句来进行改造,改造后的代码如下所示:

1
2
3
4
5
6
7
void main(){
var temp = 0;
do{
print("这是一个do-while循环: "+temp.toString());
temp++;
}while(temp < 5);
}

break和continue

【break】break用于跳出循环,下面的例子说明当变量的值为2时就跳出循环,如下所示:

1
2
3
4
5
6
7
8
9
void main(){
var list = [1,2,3,4];
for(var v in list){
if(v==2){
break;
}
print(v);
}
}

程序执行结果如下所示:

1
1

也就是说当v等于2时循环就结束,所以程序就输出1。
【continue】现在我们尝试将其中的break替换为continue,此时代码如下:

1
2
3
4
5
6
7
8
9
void main(){
var list = [1,2,3,4];
for(var v in list){
if(v==2){
continue;
}
print(v);
}
}

程序执行结果如下所示:

1
2
3
1
3
4

可以看到此时当v等于2时,循环只是跳出本次循环,代码还会继续执行下去。

switch和case

Dart中的switch和case语句使用“==”操作符来比较整数、字符串或者其他编译过程中的常量(也包括对象和枚举),进而实现分支的作用。请注意,switch/case语句的前后操作数必须是同一类型的对象实例。每一个非空的case字句最后都必须跟上break语句,使用default处理默认情况,也可以使用continue来跳转标签。

举个例子,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void main(){
int index = 1;
switch(index){
case 6:
print("星期六");
break;
case 7:
print("星期日");
break;
default:
print("工作日");
break;
}
}

//工作日

再来看一下使用continue来跳转标签的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void main(){
String language = "dart";
switch(language){
C:
case "java":
print("java");
break;
case "dart":
print("dart");
continue C;
default:
print("none");
break;
}
}

//输出结果
dart
java

由于language的值为dart,因此首先会匹配case "dart"的情况,然后输出dart,接着由于使用了continue C;使得代码跳转到了C:处,C处会找到离它最近的情况,然后进行输出。此处的C只是一个变量,它不需要值,名称可随意取。

assert(断言)

assert语句用于中断正常的执行流程,当assert判断条件为false时,程序将发生中断;注意assert判断的条件时任何可以转化为boolean类型的对象,也包括函数。

说白了,即assert判断为true则继续执行后续流程,如果为false则抛出一个断言错误AssertError。举个例子,如下所示:

1
2
3
4
5
void main(){
String text = "";
assert (text!= "");
print("text不是空字符串");
}

显然后续内容是无法打印输出的,原因就在于assert断言判断值为false中断了后续流程执行。

异常处理

异常表示发生了意外的错误,如果没有捕获异常,那么引发异常的程序将会被挂起,且程序将被终止运行。注意Dart中所有的异常都是非检查异常。

Dart提供了异常和错误类型以及许多预定义的子类型,当然开发者也可以自定义自己的异常,注意Dart程序可以抛出任何非空对象。

抛出异常

下面是一个抛出或者引发异常的例子:

1
throw FormatException("抛出一个异常");

也可以抛出任意对象:

1
throw "数据非法";
捕获异常

开发者可以指定一个或者两个参数来捕获异常(catch),如果使用两个那么第一个catch用于捕获异常详细信息,第二个catch则是堆栈跟踪(StackTrace对象)。举个例子,如下所示:

1
2
3
4
5
6
7
8
9
10
void main(){
try{
//...
}on Exception catch(e){
print("Exception details:\n $e");
}catch(e,s){
print("Exception details:\n $e");
print("Stack Trace:\n $e");
}
}
finally

如果开发者要求某些代码,无论是否抛出异常都可以正常运行,此时就可以使用finally字句。如果没有catch字句匹配异常,那么异常将会在finally字句执行之后被抛出。

1
2
3
4
5
6
7
8
9
10
11
12
void main(){
try{
//...
}on Exception catch(e){
print("Exception details:\n $e");
}catch(e,s){
print("Exception details:\n $e");
print("Stack Trace:\n $e");
}finally{
print("do something");
}
}

小结

本篇学习了Dart语言中的一些重要概念并在此基础上搭建了Dart开发环境,还学习了Dart语言中的一些基础语法,如变量和常量、基本数据类型、运算符和流程控制语句等。