Flutter空安全相关操作符

Dart 2.12引入了空安全特性,强制类型默认为非空,减少运行时错误。通过在类型后添加?允许变量可空,使用?.进行安全调用,避免空指针异常。空断言运算符(!)用于明确表示值不会为空,但要谨慎使用。late关键字用于延迟初始化,确保变量在使用前赋值。这些改进提高了代码的健壮性和安全性。
摘要由CSDN通过智能技术生成

健全的空安全已在 Dart 2.12 和 Flutter 2 中可用

需知

当你选择使用空安全时,代码中的类型将默认是非空的,意味着 除非你声明它们可空,它们的值都不能为空。有了空安全,原本处于你的 运行时 的空值引用错误将变为 编辑时 的分析错误。

? 允许变量为null

int a = null;

一般来说,int类型的变量无法赋值为null , 在加入空安全后,编译器会报错。
若你想让变量可以为 null,只需要在类型声明后加上 ?。

int? aNullableInt = null;
String? b = null;

//允许list为null
List<String>? aNullableListOfStrings;

//允许List中的元素为null
List<String?> aListOfNullableStrings = ['one', null, 'three'];

?. 具有空安全的‘.’

一般我们调用某个对象方法或者属性的时候会采用如下操作:

print(user.name);

有时我们不知道user是否为空,会加个判空操作:

if(user!=null){
print(user.name)
}

其实可以替换.?.

print(user?.name);

当user不为空时 , 此处的?.等价于.
当user为空时,将输出null。

如果想处理为空时的返回:

print(user?.name ?? '结果为null');

等价于:

if(user==null||user.name==null){
print('结果为null');
}else{
print('user.name');
}

优点就是减少代码,省略判空操作直接使用,避免为空时的报错。

! 空断言运算符

如果你确定具有可为空类型的表达式不为空,则可以使用空断言运算符 (!) 使 Dart 将其视为不可为空。通过在表达式之后增加 !,来告诉 Dart 该值不会为空,并且可以安全地将其分配给不可为空的变量。

当然,如果你错了,Dart 会在运行时抛出异常。这使得 !运算符不安全,因此除非你非常确定表达式不为空,否则不要使用它。

int? couldReturnNullButDoesnt() => -3;
int c = couldReturnNullButDoesnt()!.abs();

这里因为couldReturnNullButDoesnt方法返回常量,可确认不为null,在使用的时候就可以在后面加上!来告诉dart此表达式必不为null。

切记:在无法确认不为null的时候,千万不要使用!

late 变量将在未来初始化

一般来说,类中的字段或顶级变量应该是不可为空的,但不能立即为它们赋值。对于这种情况,请使用 late 关键字。

比如你声明了一个变量,你暂时不想赋值,但以后会赋值,可以使用late修饰(最常见的就是需要从服务器获取的数据):

late String a;

如果你确定这个属性需要在访问之前被赋值,将它标记为 late

late 会在运行时检查。所以请你仅在确定它被使用前一定会被初始化的情况下使用 late

late还有一个作用是延迟加载 ,相当于lazy的特性:

int _computeValue() {
  print('In _computeValue...');
  return 3;
}

class CachedValueProvider {
  final _cache = _computeValue();
  int get value => _cache;
}

void main() {
  print('Calling constructor...');
  var provider = CachedValueProvider();
  print('Getting value...');
  print('The value is ${provider.value}!');
}

以上代码,输出内容是:

Calling constructor…
In _computeValue…
Getting value…
The value is 3!

如果将_cache用late修饰,那么打印结果将会改变:

Calling constructor…
Getting value…
In _computeValue…
The value is 3!

不妨运行一下试试.

好的,以下是一个使用 Sqflite 的 Flutter 代码样例,使用了安全: ```dart import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; class DatabaseHelper { static const _databaseName = 'my_database.db'; static const _databaseVersion = 1; static Database? _database; // 私有构造函数 DatabaseHelper._(); static final DatabaseHelper instance = DatabaseHelper._(); Future<Database> get database async { if (_database != null) return _database!; _database = await _initDatabase(); return _database!; } Future<Database> _initDatabase() async { final dbPath = await getDatabasesPath(); final path = join(dbPath, _databaseName); return await openDatabase( path, version: _databaseVersion, onCreate: _onCreate, ); } Future<void> _onCreate(Database db, int version) async { await db.execute(''' CREATE TABLE my_table ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER NOT NULL ) '''); } Future<int> insert(Map<String, Object?> row) async { final db = await instance.database; return await db.insert('my_table', row, conflictAlgorithm: ConflictAlgorithm.replace); } Future<List<Map<String, Object?>>> queryAllRows() async { final db = await instance.database; return await db.query('my_table'); } Future<int> update(Map<String, Object?> row) async { final db = await instance.database; final id = row['id']; return await db.update('my_table', row, where: 'id = ?', whereArgs: [id]); } Future<int> delete(int id) async { final db = await instance.database; return await db.delete('my_table', where: 'id = ?', whereArgs: [id]); } } ``` 这个样例代码定义了一个 `DatabaseHelper` 类,提供了对 SQLite 数据库的基本操作,并且使用了安全特性。 在这个代码中,我们使用了 `late` 修饰符来延迟初始化 `_database` 变量,同时使用了 `?` 来标记这个变量是可的。在 `get database` 方法中,我们使用了 `!` 来断言 `_database` 不为。 在这个代码中,我们还使用了非断言操作符 `!`,来确保变量不为。同时,我们也使用了值合并操作符 `??`,来提供默认值。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值