本文学习和引用自《Flutter实战·第二版》:作者:杜文
类似于 JavaScript 中的var,它可以接收任何类型的变量,但最大的不同是 Dart 中 var 变量一旦赋值,类型便会确定,则不能再改变其类型:
var name = "李四"
/// 对
name = "张三"
/// 错
name = 1000
Object 是 Dart 所有对象的根基类,也就是说在 Dart 中所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象,且后期可以改变赋值的类型。但是声明的对象只能使用 Object 的属性与方法, 否则编译器会报错。
Object t = 1000
t = "张三"
print(t.length) // 错
任何类型的数据都可以赋值给dynamic声明的对象,且声明的变量都可以赋值任意对象,且后期可以改变赋值的类型。而编译器会提供所有可能的组合给声明的对象,这个特点使得我们在使用它时需要格外注意,比如下面代码在编译时不会报错,而在运行时会报错:
dynamic t
t = "王五"
print(t.xxx) // 错
如果您从未打算更改一个变量,那么可以使用 final。一个 final 变量只能被设置一次。它是一个运行时常量,final变量在运行时才知道其值,用于防止变量在程序运行期间被改变。
如果您从未打算更改一个变量,那么可以使用 const。与final的区别是,const 变量是一个编译时常量,其值必须在声明时就确定。(编译时直接替换为常量值)用于创建编译时常量,以便进行性能优化。
Dart 中一切都是对象,这意味着如果我们定义一个数字,在初始化它之前如果我们使用了它,假如没有某种检查机制,则不会报错。如下:
test() {
int i;
print(i*8); // 错
}
在 Dart 引入空安全之后,如果一个变量没有初始化,则不能使用它,否则编译器会报错:
int a = 10
声明时候可以加上?,指定变量是可空:
String? name;
如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错:
late int c;
c = 100
如果一个变量我们定义为可空类型,且判空了,但是预处理器仍然有可能识别不出,这时我们就要在变量后面加一个!
符号,告诉预处理器它已经不是null了。
class Test() {
int? d;
log() {
if (d! = null) {
print(d! * 100)
}
}
}
如果函数变量可空时,调用的时候可以用语法糖:
fun?.call()
// 同时声明
var (a, [b, c]) = ('str', [1, 2])
// 同时声明
var (c, d) = ('left', 'right');
// 交换2个值
(c, d) = (d, c)
// 解构
var (name, age) = userInfo(json)
// 省略符
var (a, b, ...rest) = [1, 2, 3, 4, 5, 6] // 1 2 [3,4,5,6]
var (a, b, ...rest, c, d) = [1, 2, 3, 4, 5, 6] // 1 2 [3,4] 5 6
var (a, b, ..., c, d) = [1, 2, 3, 4, 5, 6] // 1 2 5 6
符号 | 意义 | 描述 |
---|---|---|
+ | 加 | - |
- | 减 | - |
* | 乘 | - |
/ | 除 | - |
~/ | 除 | 返回整数结果 |
% | 取余 | 获取整数除法的余数 |
符号 | 意义 | 描述 |
---|---|---|
== | 平等 | - |
!= | 不相等 | - |
> | 大于 | - |
< | 小于 | - |
>= | 大于或等于 | - |
<= | 小于或等于 | - |
符号 | 意义 | 描述 |
---|---|---|
! | 反转 | - |
|| | 或者 | - |
&& | 并且 | - |
符号 | 意义 | 描述 |
---|---|---|
= | 赋值 | - |
*= | 乘法赋值 | - |
+= | 加法赋值 | - |
-= | 减法赋值 | - |
/= | 除法赋值 | - |
%= | 取模赋值 | - |
~/= | 返回除法整数结果赋值 | - |
= | 按位或赋值 | |
&= | 按位与赋值 | - |
^= | 按位异或赋值 | - |
<<= | 左移赋值 | - |
>>= | 右移赋值(保留符号位) | - |
>>>= | 右移赋值(无符号右移) | - |
符号 | 意义 | 描述 |
---|---|---|
as | 类型转换断言 | - |
is | 如果对象具有指定的类型,则为 True | - |
is! | 如果对象没有指定的类型,则为 True | - |
// 如果您不确定该对象的类型是否为Person,则在使用对象之前用is检查
if (employee is Person) {
employee.firstName = 'Bob';
}
符号 | 意义 | 描述 |
---|---|---|
& | 与 | - |
| | 或 | - |
^ | 异或 | - |
<< | 左移 | - |
>> | 右移 | - |
>>> | 无符号右移 | - |
语法 | 意义 | 描述 |
---|---|---|
condition ? expr1 : expr2 | 赋值 | 三元表达式 |
expr1 ?? expr2 | 赋值 | 如果 expr1 为非 null,则返回其值; 否则,计算并返回 expr2 的值 |
?.xxx | 短路 | 条件成员访问 |
! | 断言 | 将表达式强制转换为其基础不可为 null 的类型 |
级联允许您在同一对象上,进行一系列操作。
// 级联语法
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
// 等价于如下语法
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
// 级联语法
querySelector('#confirm')
?..text = 'Confirm'
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();
// 等价于如下语法
var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();
关键字 | 描述 |
---|---|
int | 不大于 64 位的整数值 |
double | 64 位(双精度)浮点数 |
String | 字符串,多行字符串可以用’‘‘xxx’’’ |
bool | 字符串 |
Set | 集 |
Map | 地图 |
List | 列表 |
Symbol | 符号 |
Null | null |
record | 记录 |
typedef | 类型别名 |
int size = 2;
// 条件判断
switch (size) {
case 1:
print('一');
case [2, 3]:
print('二 and 三')
case [4 || 5]:
print('四 or 五')
case >= 6 && <= 10
print('六 to 十')
}
// 条件赋值
var bg = Color.green
var isPrimary = switch (bg) {
Color.red || Color.yellow || Color.blue => true,
_ => false
}
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
Map<String, int> listMap = {
'a': 23,
'b': 100,
};
for (final MapEntry(key: key, value: value) in listMap.entries) {
print('键:$key 值:$value');
}
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
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();
}
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
// 接受一个名为pair的参数。如果pair的类型是[int x, int y],则返回一个Point(x, y)对象
if (pair case [int x, int y]) return Point(x, y);
异常捕获和JavaScript差不多
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 特定的异常
buyMoreLlamas();
} on Exception catch (e) {
// 任何其他的例外
print('Unknown exception: $e');
} catch (e) {
// 没有指定类型,处理所有类型
print('Something really unknown: $e');
} finally {
cleanLlamaStalls();
}
void misbehave() {
try {
dynamic foo = true;
print(foo++); // 运行时错误
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // 允许调用者看到异常
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
在开发过程中,使用断言语句,如果布尔条件为false,则触发。如果条件为true,则不触发。在生产代码中,断言将被忽略。
// assert(条件, 可选消息)
var sizi = 101;
assert(size < 100, "Error:size 小于 100!");
Dart是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征。
bool isNoble(int ) {
return atomicNumber > 40;
}
bool isNoble (int atomicNumber) => atomicNumber > 40;
//定义函数execute,它的参数类型为函数
void execute(var callback) {
// 执行传入的函数
callback();
}
// 调用execute,将箭头函数作为参数传递
execute(() => print("xxx"))
String say(String a, String b, [String? c]) {
var result = '$a and $b';
if (c != null) {
result = '$result and $c';
}
return result;
}
//设置[a]和[b]标志
void enableFlags({bool a, bool b}) {
// ...
}
// 调用函数时,可以使用指定命名参数
enableFlags(bold: true, hidden: false)
Dart 是不支持多继承的,但是它支持 mixin。可以定义几个 mixin,然后通过 with 关键字将它们组合成不同的类(同名会被最后的覆盖)。如下例子:
class Person {
say() {
print('say');
}
}
mixin Eat {
eat() {
print('eat');
}
}
mixin Walk {
walk() {
print('walk');
}
}
mixin Code {
code() {
print('key');
}
}
class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}
Dart类库有非常多的返回Future或者Stream对象的函数,这些函数被称为异步函数。
Future与JavaScript中的Promise非常相似。
// 使用Future.delayed 创建了一个延时任务,2秒后返回结果字符串,然后在then中接收异步结果并打印
Future.delayed(Duration(seconds: 2),(){
return "hi world!";
}).then((data){
// 执行成功
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
Future.wait([
// 2秒后返回结果
Future.delayed(Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
// 执行接下来的操作
} catch(e){
// 错误处理
print(e);
}
}
Stream 也是用于接收异步事件数据,和 Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){});
// 上述代码依次输出
// hello 1
// Error
// hello 3
本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~
往期文章
个人主页