Dart 是谷歌于2011年10月10日发布一门开源编程语言(日子挑的不错)。2018年之前一直处于蛰伏状态,flutter 之后声名雀起,一发不可收拾!
Dart 的存在的存在的意义是什么呢?看一下官网的概述:
Dart is a client-optimized language for developing fast apps on any platform. Its goal is to offer the most productive programming language for multi-platform development, paired with a flexible execution runtime platform for app frameworks.
废话说完了,进入正题!
Hello Dart
怎么能少得了 Hello World !
// 程序入口函数
void main() {
// 函数调用
printHelloWorld();
}
// 定义函数 printHelloWorld
void printHelloWorld() {
// 实现,打印 Hello World
print("Hello World !");
}
如上,一个简单的 Hello World 就写完了。可以自己打开 DartPad 进行练手!
Dart 语法学习的过程中均可在其上进行练习,灰常方便!
Dart 语言特点
Dart 语言具有以下特点:
0、编译型;
1、强类型(Dart 2 才是);
2、面向对象,一切皆对象,数字、函数、null 都是对象;
语法
变量
使用关键字 var
进行变量的声明。
// 声明一个字符串变量 name 并赋值 Yuri
var name = "Yuri";
// 声明一个变量 temperature 并赋值 35.0
var temperature = 35.0;
由于 Dart 有类型推断机制,name 会被自动判断为 String
类型。
也可以使用类型显式的声明一个变量:
String name = "Yuri";
double temperature = 28.5;
还可以使用 dynamic
或 Object
声明一个变量。但 dynamic
和 Object
的变量可以在后期改变赋值的类型,而 Var 声明的变量则不可以。 dynamic
这个特性与 Objective-C 中的 id
作用很像. dynamic 的这个特点使得我们在使用它时格外需要注意,因为很容易引入运行时错误。
dynamic name = "Yuri";
Object temperature = 28.5;
print("$name, $temperature");
// 打印结果:Yuri, 28.5
name = 28.5;
temperature = "Yuri";
print("$name, $temperature");
// 打印结果:28.5, Yuri
常量
使用关键字 final
或 const
声明一个常量。
// 使用 final 声明一个 sex 的常量
final sex = "male";
// 使用 const 声明一个 nickName 的常量
const nickName = "Kitty";
使用 final
和 Const
声明的常量的值不能被修改。
final
和 const
的区别在哪呢?
const
定义的常量在编译时就已经固定,final
定义的常量则在第一次使用时才被初始化。
Dart 内建类型
Number
Number 有两种类型 int
和 double
。
// 定义一个 int 类型变量
int x = 1;
// 定义一个 double 类型变量
double y = 3.14;
int
整数值不大于64位, 具体取决于平台。 在 Dart VM 上, 值的范围从 -263 到 263 - 1. Dart 被编译为 JavaScript 时,使用 JavaScript numbers, 值的范围从 -253 到 253 - 1.
double
: 64位(双精度)浮点数,依据 IEEE 754 标准。
String
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}
的方式内嵌表达式。 如果表达式是一个标识符,则{}
可以省略。
var s = 'string interpolation';
print("Dart has $s, which is very handy.");
在 Dart 中通过调用就对象的 toString()
方法来得到对象相应的字符串。
String oneAsString = 1.toString();
assert(oneAsString == '1');
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
可以使用 +
运算符来把多个字符串连接为一个,也可以把多个字面量字符串写在一起来实现字符串连接。
var s1 = 'String '
'concatenation'
" works even over line breaks.";
print(s1);
// 打印结果: String concatenation works even over line breaks.
var s2 = 'The + operator ' + 'works, as well.';
print(s2);
// 打印结果:The + operator works, as well.
Boolean
bool
,表示布尔值,有 true
和 false
两个值。
bool isSunny = true;
bool isRainy = false;
List (也被称为 Array)
List 表示有序集合。
// 定义一个 整形 的数组字面量
var list = [1, 2, 3];
// 获取数组长度
var length = list.length;
// 访问数组元素. List 元素的下标也是从 0 开始的
var secondValue = list[1];
Map
通常来说, Map
是用来关联 keys 和 values 的对象。
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
也可以使用 Map 的构造函数创建对象。
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';
向 Map 添加一个 key-value
gifts["sixth"] = "cake";
访问 Map 中的 value
var sixthGift = gifts["sixth"];
assert(sixthGift == "cake");
Set
Set 表示无序元素的集合,集合内元素唯一。
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
创建一个空集
var names = <String>{};
向 set 中添加元素
names.add("1");
names.addAll({"2", "3"});
Rune (用于在字符串中表示 Unicode 字符)
Dart 字符串是一系列 UTF-16 编码单元,即每个字符占 16 位, 而 Unicode 则是 32 位的,因此 Dart 字符串中表示 32 位 Unicode 值需要特殊语法支持。
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(new String.fromCharCodes(input));
Symbol
一个 Symbol 对象表示 Dart 程序中声明的运算符或者标识符。 你也许永远都不需要使用 Symbol ,但要按名称引用标识符的 API 时, Symbol 就非常有用了。 因为代码压缩后会改变标识符的名称,但不会改变标识符的符号。 通过字面量 Symbol ,也就是标识符前面添加一个 # 号,来获取标识符的 Symbol 。
#radix
#bar
Symbol 字面量是编译时常量。
函数
Dart 中一切皆对象。函数也是对象,其对应的类型为 Function
。
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
在 Effective Dart 中推荐 公共API中声明类型, 但是省略了类型声明,函数依旧是可以正常使用的
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果函数中只有一句表达式,可以使用简写语法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr
语法是 { return expr; }
的简写。 =>
符号 有时也被称为 箭头 语法。
在 Dart 语言中,函数是一等对象(难道还有二等,三等?)。
函数可以作为另一个函数的参数,同时也可以把函数赋值给一个变量。
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 将 printElement 函数作为参数传递。
list.forEach(printElement);
// 将函数作为值赋给变量
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函数
一般情况下函数是有名字的,把没有名字的函数叫做匿名函数。
匿名函数有时也被称为 lambda 或者 closure。
在将函数作为值赋值给变量时,我们用的就是一个匿名函数。
可选参数
可选参数分命名参数和位置参数。一个参数只能选择其中一种进行修饰。
命名可选参数
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {
...
}
调用
enableFlags(bold: true, hidden: false);
命名可选参数可以用 @required 进行修饰,表示在函数调用时该参数不可缺少。
const Scrollbar({Key key, @required Widget child})
此时 Scrollbar 是一个构造函数, 当 child 参数缺少时,分析器会提示错误。
位置可选参数
将参数放到 []
中来标记参数是可选的
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
默认参数
在定义函数时,我们可以给参数一个默认值。
/// 设置 [bold] 和 [hidden] 标志 ...
void enableFlags({bool bold = false, bool hidden = false}) {
...
}
// bold 值为 true; hidden 值为 false.
enableFlags(bold: true);
运算符
算术运算符
操作符 | 功能 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
~/ | 除法取整 |
% | 模(余数) |
除了上面的基本的算术运算符,Dart 同样也支持带有前缀的自增和自减运算符。
++expr
, expr++
,--expr
,expr--
/// 基本操作运算符示例
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 结果是双浮点型
assert(5 ~/ 2 == 2); // 结果是整型
assert(5 % 2 == 1); // 余数
/// 自增自减运算符示例
var a, b;
a = 0;
b = ++a; // a自加后赋值给b。
assert(a == b); // 1 == 1
a = 0;
b = a++; // a先赋值给b后,a自加。
assert(a != b); // 1 != 0
a = 0;
b = --a; // a自减后赋值给b。
assert(a == b); // -1 == -1
a = 0;
b = a--; // a先赋值给b后,a自减。
assert(a != b); // -1 != 0
关系运算符
操作符 | 功能 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
比较简单,不再示例。
类型判定运算符
操作符 | 功能 |
---|---|
as | 类型转化 |
is | 类型判断(True if the object has the specified type) |
is! | 类型判断(False if the object has the specified type) |
is
比较好理解,是就返回 true,不是就返回 false;
而 is!
意义则相反,不是就返回 true,是就返回 false;
个人感觉大部分情况下,is
就够了!
赋值运算符
=
是基本的赋值运算符,通过与其它操作符的组合,会产生许多其它的复合赋值运算符。如下
= | -= | /= | %= | >>= | ^= |
---|---|---|---|---|---|
+= | *= | ~/= | <<= | &= | |= |
比较简单,不再示例。
逻辑运算符
操作符 | 含义 |
---|---|
&& | 与 |
|| | 或 |
! | 非 |
不再示例。
按位和移位运算符
操作符 | 含义 |
---|---|
& | 按位与(AND) |
| | 按位或(OR) |
^ | 按位异或(XOR) |
~expr | 取反(Unary bitwise complement (0s become 1s; 1s become 0s)) |
<< | 左移(Shift left) |
>> | 右移(Shift right) |
条件表达式
condition ? expr1 : expr2
如果条件为 true, 执行 expr1 (并返回它的值): 否则, 执行并返回 expr2 的值。
var visibility = isPublic ? 'public' : 'private';
expr1 ?? expr2
如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。
String playerName(String name) => name ?? 'Guest';
级联运算符
级联运算符 ..
可以实现对同一个对像进行一系列的操作。除了调用函数, 还可以访问同一对象上的字段属性。
querySelector('#confirm') // 获取对象。
..text = 'Confirm' // 调用成员变量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
这个运算符在 iOS 开发过程中没有遇到过,应该是 Dart 特胡的语法糖。
其它运算符
Operator | Name | Meaning |
---|---|---|
() | Function application | Represents a function call |
[] | List access | Refers to the value at the specified index in the list |
. | Member access | Refers to a property of an expression; example: foo.bar selects property bar from expression foo |
?. | Conditional member access | Like ., but the leftmost operand can be null; example: foo?.bar selects property bar from expression foo unless foo is null (in which case the value of foo?.bar is null) |
控制流程语句
if ... else ...
注意:条件语句必须是布尔值
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
for loops
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
while and do-while loops
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
break and continue
break: 停止程序循环。
continue:跳过当次循环。
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
switch and case
注意:正常情况下,case 中的 break 不可省略。
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
assert
如果 assert 语句中的布尔条件为 false , 那么正常的程序执行流程会被中断。
// 确认变量值不为空。
assert(text != null);
// 确认变量值小于100。
assert(number < 100);
// 确认 URL 是否是 https 类型。
assert(urlString.startsWith('https'));
异常处理
Dart 可以抛出和捕获异常。
throw
throw 用于抛出异常。
当函数执行过程中出现了异常,可以通过 throw 将异常抛出。异常可以是 Exception 或 Error,或其它任何非 null 对象。当抛出异常时,程序也将会被终止。
throw FormatException('Expected at least 1 section');
以下示例抛出了一条字符串消息
throw 'Out of llamas!';
catch
捕获异常可以避免异常继续传递.
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
通过指定多个 catch 语句,可以处理可能抛出多种类型异常的代码。 与抛出异常类型匹配的第一个 catch 语句处理异常。 如果 catch 语句未指定类型, 则该语句可以处理任何类型的抛出对象:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一个特殊的异常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何异常
print('Unknown exception: $e');
} catch (e) {
// 没有指定的类型,处理所有异常
print('Something really unknown: $e');
}
如上述代码所示,捕获语句中可以同时使用 on
和 catch
,也可以单独分开使用。 使用 on
来指定异常类型, 使用 catch
来 捕获异常对象。
catch()
函数可以指定1到2个参数, 第一个参数为抛出的异常对象, 第二个为堆栈信息 ( 一个 StackTrace 对象 )。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
如果仅需要部分处理异常, 那么可以使用关键字 rethrow 将异常重新抛出。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
finally
不管是否抛出异常, finally 中的代码都会被执行。 如果 catch 没有匹配到异常, 异常会在 finally 执行完成后,再次被抛出:
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
任何匹配的 catch 执行完成后,再执行 finally :
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}