Dart:如何正确处理空值安全?
Dart: How to properly handle null-safety?
我已经将我的项目升级到 null-safety,这有点令人困惑,因为如果我包装成
if(someObject.field != null) {
doSomething(someObject.field); // error, can't assign String? to String
}
需要不可为空的方法调用 属性 并且我尝试传递的变量可以为空,然后我收到类型错误,无法将可为空的值分配给不可为空的类型。
但是当我这样做的时候
String? someObjectField = someObject!.field;
if(someObjectField != null) {
doSometing(someObjectField); // Can assign
}
它按预期工作。
doSomething = (String foo) {}
例如:
class Person {
final String name;
Person(this.name);
}
Function test = () {
Map<String, String?> pers = {
'name': 'John',
};
if(pers['name'] != null) {
Person(pers['name']); // Error, even if it will be never executed
Person(pers['name'] as String); // no error
Person(pers['name']!); // no error
}
};
如果我这样做:
if (widget.event != null && widget.event.featuredImage != null)
然后它在第二个语句中抱怨接收器 (widget.event) 可以为 null,我需要使用 !
,但是第二个语句不应该执行并且它不应该导致运行时异常。
所以需要修改为:
if (widget.event != null && widget.event!.featuredImage != null)
但是当我尝试在 Flutter 中使用嵌套小部件时,即使我使用 if
作为包装器,我仍然需要在所有地方添加 !
Stack(
children: [
// Add Container with image only when event and futured image are not null
if (widget.event != null && widget.event!.featuredImage != null) ...[
Container(
height: 250,
decoration: BoxDecoration(
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(widget.event!.featuredImage!), // here i Need to use ! to satisfy the compiler
),
),
),
],
],
)
或者我可以将变量提取到另一个 String? image = widget.event!.featuredImage
,然后将 if
语句修改为 if(image != null)
并使用像 NetworkImage(image)
这样的小部件,它按预期工作。
与检测我是否在上述条件下检查 null 的 TypeScript 相比,这对我来说毫无意义。
长话短说,即使我检查 render/not-render 组件的空值,我仍然需要使用 !
.
有什么明显的我遗漏的东西吗?
提前致谢
既然你将它与 TypeScript 进行了比较,是的,你错过了一些东西。
Typescript 是一团糟,只能在非常有限的环境中工作,“工作”被严重夸大了。例如,您可以在打字稿中编写一个方法,该方法接受一个字符串,然后在运行时发现它实际上不是一个字符串,令人惊讶的是,它是一个完全不同的类型。 JavaScript 的欢乐。与 JS 相比,称 TypeScript 为“类型安全”是正确的,与实际编译语言相比是荒谬的。
所以您忽略了一个事实,即 Dart 编译器可以保证 一旦您检查某项内容就不会为空。为此,它需要额外的约束。例如,您可以让 getter 每次调用它们时都不会 return 相同的值。例如,根据 getter 的代码,您的调用很容易在第一次和第二次调用之间 return 不同 值。或者您可以使用继承和多态性来构建一些问题更多的结构。有关有趣的示例,请参见 。所以你需要有一个局部变量,保证具有相同的值,除非明确更改。
您的 if (widget.event != null && widget.event.featuredImage != null)
示例可以轻松修改为:
final image = widget?.event?.featuredImage;
Stack(
children: [
// Add Container with image only when event and futured image are not null
if (image != null) ...[
Container(
height: 250,
decoration: BoxDecoration(
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(image),
),
),
),
],
],
)
是的,您必须实现一些微小的逻辑,您不能只在代码上添加 ?
和 !
就可以像以前一样运行。但是一旦你理解了逻辑上的小变化是什么,它就很容易了。
我已经将我的项目升级到 null-safety,这有点令人困惑,因为如果我包装成
if(someObject.field != null) {
doSomething(someObject.field); // error, can't assign String? to String
}
需要不可为空的方法调用 属性 并且我尝试传递的变量可以为空,然后我收到类型错误,无法将可为空的值分配给不可为空的类型。
但是当我这样做的时候
String? someObjectField = someObject!.field;
if(someObjectField != null) {
doSometing(someObjectField); // Can assign
}
它按预期工作。
doSomething = (String foo) {}
例如:
class Person {
final String name;
Person(this.name);
}
Function test = () {
Map<String, String?> pers = {
'name': 'John',
};
if(pers['name'] != null) {
Person(pers['name']); // Error, even if it will be never executed
Person(pers['name'] as String); // no error
Person(pers['name']!); // no error
}
};
如果我这样做:
if (widget.event != null && widget.event.featuredImage != null)
然后它在第二个语句中抱怨接收器 (widget.event) 可以为 null,我需要使用 !
,但是第二个语句不应该执行并且它不应该导致运行时异常。
所以需要修改为:
if (widget.event != null && widget.event!.featuredImage != null)
但是当我尝试在 Flutter 中使用嵌套小部件时,即使我使用 if
作为包装器,我仍然需要在所有地方添加 !
Stack(
children: [
// Add Container with image only when event and futured image are not null
if (widget.event != null && widget.event!.featuredImage != null) ...[
Container(
height: 250,
decoration: BoxDecoration(
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(widget.event!.featuredImage!), // here i Need to use ! to satisfy the compiler
),
),
),
],
],
)
或者我可以将变量提取到另一个 String? image = widget.event!.featuredImage
,然后将 if
语句修改为 if(image != null)
并使用像 NetworkImage(image)
这样的小部件,它按预期工作。
与检测我是否在上述条件下检查 null 的 TypeScript 相比,这对我来说毫无意义。
长话短说,即使我检查 render/not-render 组件的空值,我仍然需要使用 !
.
有什么明显的我遗漏的东西吗?
提前致谢
既然你将它与 TypeScript 进行了比较,是的,你错过了一些东西。
Typescript 是一团糟,只能在非常有限的环境中工作,“工作”被严重夸大了。例如,您可以在打字稿中编写一个方法,该方法接受一个字符串,然后在运行时发现它实际上不是一个字符串,令人惊讶的是,它是一个完全不同的类型。 JavaScript 的欢乐。与 JS 相比,称 TypeScript 为“类型安全”是正确的,与实际编译语言相比是荒谬的。
所以您忽略了一个事实,即 Dart 编译器可以保证 一旦您检查某项内容就不会为空。为此,它需要额外的约束。例如,您可以让 getter 每次调用它们时都不会 return 相同的值。例如,根据 getter 的代码,您的调用很容易在第一次和第二次调用之间 return 不同 值。或者您可以使用继承和多态性来构建一些问题更多的结构。有关有趣的示例,请参见
您的 if (widget.event != null && widget.event.featuredImage != null)
示例可以轻松修改为:
final image = widget?.event?.featuredImage;
Stack(
children: [
// Add Container with image only when event and futured image are not null
if (image != null) ...[
Container(
height: 250,
decoration: BoxDecoration(
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(image),
),
),
),
],
],
)
是的,您必须实现一些微小的逻辑,您不能只在代码上添加 ?
和 !
就可以像以前一样运行。但是一旦你理解了逻辑上的小变化是什么,它就很容易了。