飞镖 | Flutter:如何在 null-safety 下从 Map 传递函数?为什么需要 bang 运算符?

Dart | Flutter: How do I pass a function from a Map under null-safety? Why is a bang operator necessary?

背景:

我一直在研究如何使用 dart 代码使用 Map 传递函数。但是,我现在被难住了。在使用空安全时使用 DartPad 时,我从以下代码中得到了一个意外的空值:

void main() {
Map<String, Function> fruits = Map();
  fruits['apple'] = appleDescription;
  fruits['banana'] = bananaDescription;
  fruits['grape'] = grapeDescription;
  
  exec(fruits['grape']!);
}

void appleDescription() => print('This fruit tastes like red!');
void bananaDescription() => print('This fruit tastes like yellow!');
void grapeDescription() => print('This fruit tastes like purple!');

void exec(Function f) {
    print(f());
}

DartPad控制台如下图所示:

问题:

我想答案会很简单,但我已经为此苦苦挣扎了一段时间。我的问题是:

  1. 我只希望 'This fruit tastes like purple!' 打印在控制台中,所以我一定在这里遗漏了一些东西。我是否从地图中正确地传递了这个函数,或者是否有一种 null 更安全的方法来传递它?

  2. 我想知道为什么在调用 exec() 函数时必须使用 bang 运算符。因为我定义了 fruits 映射包含 ,所以编译器会理解它必须存在。我错过了什么?

再次感谢社区的任何建议。

更新:

我使用以下代码删除了 bang 运算符,并在下面的答案中进行了更正:

void main() {
Map<String, Function> fruits = Map();
  fruits['apple'] = appleDescription;
  fruits['banana'] = bananaDescription;
  fruits['cranberry'] = grapeDescription;
  
  exec(fruits['cranberry']??= (){print('');});
}

void appleDescription() => print('This fruit tastes like red!');
void bananaDescription() => print('This fruit tastes like yellow!');
void grapeDescription() => print('This fruit tastes like purple!');

void exec(Function f) {
    f();
}

您的 exec 函数尝试打印 f() 函数的结果,该函数本身会打印您正在等待的短语。

所以基本上 :

  1. 密码进入exec
  2. 调用 f()
  3. f() 打印 This fruit tastes like purple! 和 returns void
  4. exec 中的 print 方法打印 return 值 => null

总而言之,您正在打印 print 函数的 return 值。

为了让您的代码按预期运行,您应该使用

void exec(Function f) {
    f();
}

要回答您的第二个问题,如果您不向其传递现有密钥,Map 可以 return null。这就是你应该使用 bang 的原因,因为不能保证 Map 的 return 是非空的。