Null Assertions在null-safe模式下以及如何尽量避免

huangapple go评论62阅读模式
英文:

Null Assertions in null-safe mode and How to Avoid If Possible

问题

学习Dart并使用dart_code_metrics确保我写的代码符合期望。其中一个启用的规则是avoid-non-null-assertion

请注意,下面的代码是为了重现在一个较大的代码库中遇到的问题,其中unitString的值是从JSON文件中获取的。因此,程序无法控制JSON文件中指定的内容。

从pubspec.yaml中:

environment:
  sdk: '>=2.15.0 <3.0.0'
// ignore_for_file: avoid_print
import 'package:qty/qty.dart';

void main() {
  const String unitString = 'in';
  // 如果unitString不是长度单位,则unit.Width返回null。
  if (Length().unitWith(symbol: unitString) == null) {
    print('不支持单位 $unitString。');
  } else {
    // 使用!会触发避免非空断言的警告。
    final Unit<Length>? units = Length().unitWith(symbol: unitString)!;
    final qty = Quantity(amount: 0.0, unit: units!);
    print('Qty = $qty');
  }
}

如果我不使用!,那么会得到以下类型错误:

类型为'Unit<Length>?'的值无法赋给类型为'Unit<Length>'的变量。
尝试更改变量的类型,或将右侧的类型转换为'Unit<Length>'。

将右侧类型转换为 Unit<Length> 会修复上述错误,但在实例化Quantity()时会引发新的错误,因为构造函数需要 Unit<Length> 而不是 Unit<Length>?。我假设有解决办法,但我是Dart的新手,无法构造出正确的搜索查询来找到答案。

我该如何修改示例代码以使Dart和dart_code_metrics满意?

英文:

Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.

Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.

From pubspec.yaml

environment:
  sdk: &#39;&gt;=2.15.0 &lt;3.0.0&#39;

// ignore_for_file: avoid_print
import &#39;package:qty/qty.dart&#39;;

void main() {
  const String unitString = &#39;in&#39;;
  // unit.Width returns null if unitString is not a unit of Length.
  if (Length().unitWith(symbol: unitString) == null) {
    print(&#39;units $unitString not supported.&#39;);
  } else {
    // The following line triggers avoid-non-null-assertion with the use of !. 
    final Unit&lt;Length&gt; units = Length().unitWith(symbol: unitString)!; 
    final qty = Quantity(amount: 0.0, unit: units);
    print(&#39;Qty = $qty&#39;);
  }
}

If I don't use ! then I get the following type error:

A value of type &#39;Unit&lt;Length&gt;?&#39; can&#39;t be assigned to a variable of type &#39;Unit&lt;Length&gt;&#39;.
Try changing the type of the variable, or casting the right-hand type to &#39;Unit&lt;Length&gt;&#39;.

Casting the right-hand side to

Unit&lt;Length&gt; 

fixes the above error but cause a new error when instantiating Quantity() since the constructor expects

Unit&lt;Length&gt; 

and not

Unit&lt;Length&gt;?

I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.

How can I modify the sample code to make Dart and dart_code_metrics happy?

答案1

得分: 0

你检查在使用值之前检查null的想法是好的,只是没有正确实现。Dart会在你使用if检查null自动将可空类型提升为非空类型,但在这种情况下,你需要使用临时变量。

void main() {
  const String unitString = 'in';

  //使用临时变量,你可以指定类型而不仅仅使用final
  final temp = Length().unitWith(symbol: unitString);
  if (temp == null) {
    print('单位 $unitString 不受支持。');
  } else {
    final Unit<Length> units = temp; 
    final qty = Quantity(amount: 0.0, unit: units);
    print('Qty = $qty');
  }
}

基本原因是,当你第一次调用unitWith函数并发现它不为null时,不能保证再次调用时它仍然会返回非空值。我认为有另一个更详细解释这一点的SO问题,但我找不到了。

英文:

Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.

void main() {
  const String unitString = &#39;in&#39;;

  //Use a temp variable, you could specify the type instead of using just using final
  final temp = Length().unitWith(symbol: unitString);
  if (temp == null) {
    print(&#39;units $unitString not supported.&#39;);
  } else {
    final Unit&lt;Length&gt; units = temp; 
    final qty = Quantity(amount: 0.0, unit: units);
    print(&#39;Qty = $qty&#39;);
  }
}

The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.

huangapple
  • 本文由 发表于 2023年2月8日 09:00:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75380451.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定