? 代表可空类型
! 类型断言
以下是例子:
1. <Function> Null Safety:
String getData(url) {
if (url != null) {
return "response data";
}
return null; // 这里返回不能是 null 类型,因为明确要求返回 String 类型
}
String? getData(url) {
if (url != null) {
return "response data";
}
return null; // 可以正常返回
}
2. 感叹号 ! 类型断言
String? str = 'this is str value';
print(str.length); // 正常输出
String? str = 'this is str value';
str = null;
print(str.length); // 提示空安全
String? str = 'this is str value';
print(str!.length); // 如果 str不等于null,才会调用 length 方法,否则会抛出异常,需要用try包裹
3. 备忘:以此类推
Articles.fromJson(Map<String, dynamic> json)
: this(
id: json['id'] ?? '', // <--- change this
topic: json['topic'] as String ?? '', // <--- change this
url: json['url'] as String ?? '', // <--- change this
description: json['description'] as String ?? '', // <--- change this
);
// 结果输出: name: null
class Preson {
String? name;
int? age;
Preson([this.name, this.age]);
String getName() {
print("name: $name");
return this.name ?? ''; // 这里定义了返回类型
}
}
void main(List<String> args) {
Preson pople = Preson();
pople.getName(); // name: null
}
如果加上 final 关键字呢? (final 意味着必须被初始化)
那么,下面这个例子就是一个不好的写法:
class Preson {
final String? name;
final int? age;
Preson([this.name, this.age]);
String getName() {
print("name: $name");
return this.name ?? '';
}
}
void main(List<String> args) {
Preson pople = Preson();
pople.getName(); // name: null
}
既然使用 final 强制必须被初始化,那么,为什么要使用代表可空类型的?号来定义变量呢?
包括下面这种方式也应该是不推荐的(至少我目前这么认为):
class Preson {
final String? name;
final int? age;
Preson({this.name, this.age});
String getName() {
print("name: $name");
return this.name ?? '';
}
}
void main(List<String> args) {
Preson pople = Preson();
pople.getName(); // name: null
}
对应使用http或者使用dio网络请求到的json接口数据,因为并不知道json反馈的内容中是否存在字段缺失,那么,暂时的、自认为比较理想的方法:
方法1:
class Preson {
final uid;
final String? name; // json返回的不确定字段
final int? age; // 如上
// 使用 required 关键字 (Use 'required' keyword) 包括必须包含的json字段
Preson({required this.uid, this.name, this.age});
String getName() {
print("uid: $uid, name: $name, age: $age");
return this.name ?? '';
}
}
void main(List<String> args) {
Preson pople = Preson(uid: 1);
pople.getName(); // name: null
}
方法2:
class Preson {
final uid;
final String? name;
final int? age;
Preson({required this.uid, this.name, this.age});
Map<String, dynamic> getData() {
Map<String, dynamic> _tmpDict = new Map();
print("uid: $uid, name: $name, age: $age");
_tmpDict['id'] = this.uid;
_tmpDict['name'] = this.name == null ? 'default Name' : 'unknown Name';
_tmpDict['age'] = this.age == null ? 0 : this.age;
return _tmpDict;
}
}
void main(List<String> args) {
Preson pople = Preson(uid: 1);
//Map<dynamic, dynamic> testDict = pople.getData(); // not good code
//Map testDict = pople.getData(); // not good code
Map<String, dynamic> testDict = pople.getData(); // good code
print(testDict);
}