5

我有类似于这个示例代码的代码(别介意它没有意义):

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

飞镖分析器通过以下警告向我String s = myMap[1];发出警告:

“字符串?”类型的值 不能分配给“字符串”类型的变量。尝试更改变量的类型,或将右侧类型转换为“字符串”。

我看到这种情况正在发生,因为从地图中检索值可能会导致null. 为什么以下代码段会给我同样的警告?

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

4 回答 4

6

问题:

文档

如果键不存在,则 Map 类上的 index [] 运算符返回 null。这意味着该运算符的返回类型必须可以为空。

看看下面的代码。由于b中缺少键,如果通过静态分析Map,则map['b']返回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.
    
于 2021-05-27T16:02:36.180 回答
4

事情是编译器不知道地图的方法containsKey真的知道。

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

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

于 2020-12-10T14:20:45.883 回答
2

警告完全基于操作的类型operator []aMap<K,V>返回 a ,V?所以它可能是null。类型系统不知道 key 是否在 map 中,甚至不知道 map什么。

您调用另一种方法,这意味着返回值null不会改变类型,并且编译器不会得到这种含义。

于 2020-12-10T14:35:04.963 回答
0

感谢您的回答。我被尝试使用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

于 2020-12-11T16:49:46.010 回答