Dart 空安全 - 以空安全的方式从地图中检索值

Dart null safety - retrieving value from map in a null safe way

我有类似于此示例代码的代码(没关系,它没有意义):

void foo(Map<int, String> myMap) {
  String s = myMap[1];
}

dart 分析器警告我关于行 String s = myMap[1]; 的警告如下:

A value of type 'String?' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'.

我看到发生这种情况是因为从映射中检索值可能会导致 null。为什么以下代码片段会给我同样的警告?

void foo(Map<int, String> myMap) {
  if (myMap.containsKey(1)) {
    String s = myMap[1];
  }
}

问题是编译器不知道 map 的方法 containsKey 确实知道。

从理论上讲,您可以传递一些具有 containsKey 的奇怪 Map 实现,它除了检查值是否存在之外还做其他事情。

编译器只有在 100% 确定该值可能不为 null 时才会产生警告。

警告完全基于操作的类型Map<K,V> return 的 operator []V?,所以它可能是 null。 类型系统不知道键是否在映射中,甚至不知道映射 是什么 .

您调用另一个方法,这意味着 return 值不会 null 不会更改类型,并且编译器不会得到该暗示。

感谢您的回答。我对尝试使用 myMap[key] 不存在的键会引发错误的语言很感兴趣。在这种情况下,一种可能的模式是首先检查密钥是否存在(尽管这在多线程代码中可能会有问题)。但是这里没有必要进行这样的检查——可以简单地测试值是否不是 null.

void foo(Map<int, String> myMap) {
  if (myMap[1]  != null) {
    String s = myMap[1];
  }
}

在 dartlang github https://github.com/dart-lang/sdk/issues/44444 上看到关于这些内容的很好的解释。 也是 null savety https://dart.dev/null-safety/faq#how-do-i-signal-that-the-return-value-from-a-map-is-non-nullable

的官方常见问题解答

问题:

来自docs

The index [] operator on the Map class returns null if the key isn’t present. This implies that the return type of that operator must be nullable.

看看下面的代码。由于 Map 中缺少键 bmap['b'] returns null 并将其值分配给 int 会导致 runtime 错误,如果这已经通过静态分析。

Map<String, int> map = {'a': 1};
int i = map['b']; // Error: You can't assign null to a non-nullable field.

解决方案:

  • 使用??并提供默认值(推荐)

    int i = map['b'] ?? 0;
    
  • 使用 Bang ! 运算符。

    int i = map['b']!; // Caution! It causes runtime error if there's no key.
    

最好的方法是您可以创建地图的扩展。此外,您可以在找不到键时传递一个可选值。这种风格基本上Python like get on dictonary.

dynamic get(String key, {dynamic opt}) {
    if (this.containsKey(key)) {
      return this[key];
    }
    return opt;
  }
}

现在在不同的文件中,您可以导入并使用它。

dynamic val = map.get('my_key', opt: 'other_value');