Flutter 迁移到空安全,延迟还是可空?
Flutter migrating to null safety, late or nullable?
我想正确地迁移到 null 安全,但我不确定到底什么时候使用 late 以及什么时候使用 nullable。我看过Flutter's Understanding null safety article and finished the Null Safety codelabs但我不知道我是否理解正确。 Flutter 和 Dart 的新手,试图在五个不同的场景中抓住这个 null 安全迁移曲线球:
- 从 JSON 解析到 dart
- 初始化变量
- 从 MaterialPageRoute 传递数据
- http 数据库助手class
- sqflite 数据库助手class
案例一:从JSON解析到dart
我正在使用 MySQL 数据库中的 http 获取数据,并使用 quicktype.io 解析 JSON 以飞镖。我的数据模型的非空安全代码如下所示:
// To parse this JSON data, do
//
// final someList = someListFromJson(jsonString);
import 'dart:convert';
List<SomeList> someListFromJson(String str) =>
List<SomeList>.from(json.decode(str).map((x) => SomeList.fromJson(x)));
String someListToJson(List<SomeList> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SomeList {
SomeList({
this.someId,
this.somebody,
});
String someId;
String somebody;
factory SomeList.fromJson(Map<String, dynamic> json) => SomeList(
someId: json["someId"],
somebody: json["somebody"],
Map<String, dynamic> toJson() => {
"someId": someId,
"somebody": somebody,
};
}
使用dart migrate
,他们建议我Changed type 'String' to be nullable
。
但是,我知道一个事实,尽管在我的 json 数据中,someId
永远不会也不能为 null,而 somebody
可能为 null。为了初始化,我是否仍应使用 ?
可空类型?我的理解是我不应该对 somebody
使用 !
空断言运算符,因为它在技术上还没有值。那么,这是否意味着我应该改用 late
关键字?
String? someId;
String? somebody;
或
late String someId;
late String somebody;
案例 2:初始化变量
我在我的一个屏幕上的有状态小部件中调用 SomeList
作为 Future。
旧代码:
class _SomeScreenState extends State<SomeScreen > {
Future<List<VocabList>> futureList;
它再次建议我让它可以为空,如下所示:
Future<List<VocabList > >? futureList;
我的理解是否正确,我使用 ?
可空类型来初始化 Future<List<VocabList>>
?
案例三:从 MaterialPageRoute 传递数据
我正在从 MaterialPageRoute 传递数据:
MaterialPageRoute(
builder: (context) => SomeScreen(
someId: something[index].someId,
somebody: something[index].somebody,
在接收端,旧代码如下所示:
class SomeScreen extends StatefulWidget {
final String someId;
final String somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
再次建议我将我的两个最终变量 someId
和 somebody
设置为可为空,但它们应该为空还是只是迟到了?
我应该这样做吗?
class SomeScreen extends StatefulWidget {
final String? someId;
final String? somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
或
class SomeScreen extends StatefulWidget {
late final String someId;
late final String somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
案例4:http数据库助手class
我正在将带有按钮的变量 someName
传递给 http 请求。
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:test/models/something_list.dart';
List<SomethingList > _list = [];
String someName;
class Somebody {
static const String url = 'http://localhost/~idunno/api_search.php';
static Future<List<SomeList > > getData(String someName) async {
try {
http.Response response =
await http.get(Uri.parse(url + '?q=' + someName));
someName
不能为空,否则http请求会失败。我是否仍应将其声明为可为空并像这样使用 on FormatException
处理失败?
List<SomethingList > _list = [];
String? someName;
// some code omitted
on FormatException {
throw InvalidFormatException('Something is not right here');
案例5:sqflite数据库助手class
旧代码:
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// some code omitted
Future<bool > checkBookmark(String someId) async {
Database db = await instance.database;
var bookmarked = await db.query(table,
where: 'someId = ?',
whereArgs: [someId]);
return bookmarked.isEmpty ? false : true;
}
这里有两个问题:(1)像上面提到的场景一样,我是否因为初始化而使Database
和Future<Database>
可以为空? (2) Added a cast to an expression (non-downcast)
是什么意思?
建议的空安全更改:
static Database? _database;
Future<Database?> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// some code omitted
Future<bool > checkBookmark(String? someId) async {
Database db = await (instance.database as FutureOr<Database>);
var bookmarked = await db.query(table,
where: 'someId = ?',
whereArgs: [someId]);
return bookmarked.isEmpty ? false : true;
}
非常感谢任何对此的帮助,我希望这些答案也能帮助其他新编码人员迁移到 null 安全!
回答我自己的一个或多个问题...免责声明:进行以下更改后我没有出现 Dart 错误,但我的代码无法正常工作,因此解决方案可能不是 100% 正确。
案例一:从JSON解析到dart
自从 quicktype is null-safe yet, I have opted for json_serializable 做我的 JSON 到飞镖转换。
案例 2:初始化变量
我没有将 > 声明为可为空,而是向我的 FutureBuilder 添加了一个类型。
child: FutureBuilder<List<VocabList>>(
案例三:从 MaterialPageRoute 传递数据
我不再需要将变量声明为可为空。
案例 4:http 数据库助手 class
没有使用可为 null 的构造函数,而是使用了 late
。
late
字符串 someName;
案例5:sqflite数据库助手class
新代码在这里:
// Initialise the database.
// Only allow a single open connection to the database.
static Database? _database; // Added ? for null-safety
Future<Database> get database async {
if (_database != null)
return _database as Future<Database>; // Added 'as type' for null-safety
_database = await _initDatabase();
return _database as Future<Database>; // Added 'as type' for null-safety
}
如果有人发现任何错误或知道我如何才能做得更好,请告诉我!
我想正确地迁移到 null 安全,但我不确定到底什么时候使用 late 以及什么时候使用 nullable。我看过Flutter's Understanding null safety article and finished the Null Safety codelabs但我不知道我是否理解正确。 Flutter 和 Dart 的新手,试图在五个不同的场景中抓住这个 null 安全迁移曲线球:
- 从 JSON 解析到 dart
- 初始化变量
- 从 MaterialPageRoute 传递数据
- http 数据库助手class
- sqflite 数据库助手class
案例一:从JSON解析到dart
我正在使用 MySQL 数据库中的 http 获取数据,并使用 quicktype.io 解析 JSON 以飞镖。我的数据模型的非空安全代码如下所示:
// To parse this JSON data, do
//
// final someList = someListFromJson(jsonString);
import 'dart:convert';
List<SomeList> someListFromJson(String str) =>
List<SomeList>.from(json.decode(str).map((x) => SomeList.fromJson(x)));
String someListToJson(List<SomeList> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class SomeList {
SomeList({
this.someId,
this.somebody,
});
String someId;
String somebody;
factory SomeList.fromJson(Map<String, dynamic> json) => SomeList(
someId: json["someId"],
somebody: json["somebody"],
Map<String, dynamic> toJson() => {
"someId": someId,
"somebody": somebody,
};
}
使用dart migrate
,他们建议我Changed type 'String' to be nullable
。
但是,我知道一个事实,尽管在我的 json 数据中,someId
永远不会也不能为 null,而 somebody
可能为 null。为了初始化,我是否仍应使用 ?
可空类型?我的理解是我不应该对 somebody
使用 !
空断言运算符,因为它在技术上还没有值。那么,这是否意味着我应该改用 late
关键字?
String? someId;
String? somebody;
或
late String someId;
late String somebody;
案例 2:初始化变量
我在我的一个屏幕上的有状态小部件中调用 SomeList
作为 Future。
旧代码:
class _SomeScreenState extends State<SomeScreen > {
Future<List<VocabList>> futureList;
它再次建议我让它可以为空,如下所示:
Future<List<VocabList > >? futureList;
我的理解是否正确,我使用 ?
可空类型来初始化 Future<List<VocabList>>
?
案例三:从 MaterialPageRoute 传递数据
我正在从 MaterialPageRoute 传递数据:
MaterialPageRoute(
builder: (context) => SomeScreen(
someId: something[index].someId,
somebody: something[index].somebody,
在接收端,旧代码如下所示:
class SomeScreen extends StatefulWidget {
final String someId;
final String somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
再次建议我将我的两个最终变量 someId
和 somebody
设置为可为空,但它们应该为空还是只是迟到了?
我应该这样做吗?
class SomeScreen extends StatefulWidget {
final String? someId;
final String? somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
或
class SomeScreen extends StatefulWidget {
late final String someId;
late final String somebody;
SomeScreen({
Key? key,
@required this.someId,
@required this.somebody,
案例4:http数据库助手class
我正在将带有按钮的变量 someName
传递给 http 请求。
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:test/models/something_list.dart';
List<SomethingList > _list = [];
String someName;
class Somebody {
static const String url = 'http://localhost/~idunno/api_search.php';
static Future<List<SomeList > > getData(String someName) async {
try {
http.Response response =
await http.get(Uri.parse(url + '?q=' + someName));
someName
不能为空,否则http请求会失败。我是否仍应将其声明为可为空并像这样使用 on FormatException
处理失败?
List<SomethingList > _list = [];
String? someName;
// some code omitted
on FormatException {
throw InvalidFormatException('Something is not right here');
案例5:sqflite数据库助手class
旧代码:
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// some code omitted
Future<bool > checkBookmark(String someId) async {
Database db = await instance.database;
var bookmarked = await db.query(table,
where: 'someId = ?',
whereArgs: [someId]);
return bookmarked.isEmpty ? false : true;
}
这里有两个问题:(1)像上面提到的场景一样,我是否因为初始化而使Database
和Future<Database>
可以为空? (2) Added a cast to an expression (non-downcast)
是什么意思?
建议的空安全更改:
static Database? _database;
Future<Database?> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// some code omitted
Future<bool > checkBookmark(String? someId) async {
Database db = await (instance.database as FutureOr<Database>);
var bookmarked = await db.query(table,
where: 'someId = ?',
whereArgs: [someId]);
return bookmarked.isEmpty ? false : true;
}
非常感谢任何对此的帮助,我希望这些答案也能帮助其他新编码人员迁移到 null 安全!
回答我自己的一个或多个问题...免责声明:进行以下更改后我没有出现 Dart 错误,但我的代码无法正常工作,因此解决方案可能不是 100% 正确。
案例一:从JSON解析到dart
自从 quicktype is null-safe yet, I have opted for json_serializable 做我的 JSON 到飞镖转换。
案例 2:初始化变量
我没有将
child: FutureBuilder<List<VocabList>>(
案例三:从 MaterialPageRoute 传递数据
我不再需要将变量声明为可为空。
案例 4:http 数据库助手 class
没有使用可为 null 的构造函数,而是使用了 late
。
late
字符串 someName;
案例5:sqflite数据库助手class
新代码在这里:
// Initialise the database.
// Only allow a single open connection to the database.
static Database? _database; // Added ? for null-safety
Future<Database> get database async {
if (_database != null)
return _database as Future<Database>; // Added 'as type' for null-safety
_database = await _initDatabase();
return _database as Future<Database>; // Added 'as type' for null-safety
}
如果有人发现任何错误或知道我如何才能做得更好,请告诉我!