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

13.6k views Asked by At

I had code similar to this example code (never mind that it makes no sense):

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

The dart analyzer warns me about the line String s = myMap[1]; with the following warning:

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'.

I see that this is happening because retrieving a value from a map can result in null. Why does the following snippet give me the same warning?

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

There are 5 answers

0
lrn On BEST ANSWER

The warning is based entirely on the type of the operation. The operator [] of a Map<K,V> returns a V?, so it might be null. The type system doesn't know whether the key is in the map or not, or even what a map is.

That you call another method which implies that the return value won't be null doesn't change the type, and the compiler doesn't get that implication.

0
Alex Radzishevsky On

Thing is that compiler does not know that map's method containsKey really does.

Theoretically you could pass some weird Map's implementation having containsKey which does something else than checking if value exists.

Compiler will not produce warning only if it 100% sure that value might not be null.

0
SebastianJL On

Thanks for the answers. I was primed by languages where trying to use myMap[key] for a nonexistent key would throw an error. In that case a possible pattern is to check first if the key is present (although this can be problematic in multithreaded code). But here such a check is not necessary -- one can simply test if the value is not null.

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

See a good explanation along those lines on the dartlang github https://github.com/dart-lang/sdk/issues/44444. Also the official faq for null savety https://dart.dev/null-safety/faq#how-do-i-signal-that-the-return-value-from-a-map-is-non-nullable

2
CopsOnRoad On

Problem:

From the 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.

Take a look at the following code. Since the key b is missing from the Map, map['b'] returns null and assigning its value to int would have caused runtime error if this had passed the static analysis.

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

Solutions:

  • Use ?? and provide a default value (recommended)

    int i = map['b'] ?? 0;
    
  • Use the Bang ! operator.

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

Best way is that you can create your Map's Extension. Also, you can pass a optional value when key is not found. This style is basically Python like get on dictonary.

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

Now in different file, you can import it & use it.

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