我切换到声音零安全,并开始在一个简单的赋值中获得运行时错误,这在声音零安全中是不应该发生的:
final widgetOnPressed = widget.onPressed;
错误:
type '(LogData) => void' is not a subtype of type '((LogData?) => void)?'
我可以为Flutter版本2.12.0-4.1.pre
和2.13.0-0.0.pre.505
重新编程。
公关:https://github.com/flutter/devtools/pull/3971
故障线路:https://github.com/flutter/devtools/blob/9fc560ff2e6749459e2ca6a1dc00bf6fb16ed93b/packages/devtools_app/lib/src/shared/table.dart#L1184
要重新编程,请在此PR启动适用于macos的DevTools,连接到应用程序并单击选项卡"日志记录"。DevTools将在控制台中显示红色屏幕和错误。
是飞镖错误还是应用程序错误?如果是应用程序错误,我该如何调试它?
这是代码中的一个错误。
您没有说明发生了哪种错误——编译时错误还是运行时错误。我猜是运行时错误。(好吧,你确实说过要在调试器中启动它,所以这也是一个很好的提示。(
线路final widgetOnPressed = widget.onPressed;
看起来不可能发生故障。毕竟,局部变量的类型是从分配给它的表达式中推断出来的,并且该表达式的运行时值肯定是静态类型的子类型,因为类型系统是健全的!不是吗?不是吗?
不是,对不起。Dart 2的类型系统是大多数的声音,在零安全的情况下更是如此,但类泛型是协变的,这仍然是不健全的。很难找到其中一种情况,即这种不确定性显示出其丑陋的头部,但返回函数,其中参数类型是类的类型变量。
您的state类扩展了State<TableRow<T?>>
,因此widget
getter返回一个TableRow<T?>
。该类型的onPressed
具有类型ItemCallback<T?>?
,也就是void Function(T?)?
。
您创建了一个_TableRowState<LogData>
,其widget
具有静态类型TableRow<LogData?>
,但您不知何故设法将TableRow<LogData>
传递给它。没关系。类泛型是协变的,所以在编译时一切都很好。
然后你做final widgetOnPressed = widget.onPressed;
。此处widgetOnPressed
的静态类型为void Function(LogData?)
。onPressed
的实际运行时类型是void Function(LogData)
,因为它来自TableRow<LogData>
。
void Function(LogData)
不是void Function(LogData?)
,因为前者不能在后者可以使用的所有地方使用(特别是,它不能在用null
调用的地方使用(。
这种转让可能是不合理的,在这种情况下实际上也是不合理的。编译器知道这一点,并插入一个额外的检查,以确保您不会为实际无效的变量赋值。该检查触发并抛出您看到的错误。
你如何避免这种情况?
不要在需要TableRow<LogData?>
的地方创建TableRow<LogData>
。
或者将变量键入为:
final ItemCallback<T>? widgetOnPressed = widget.onPressed;
(T
上没有?
(。
或者重写所有内容,以避免返回带有协变类型参数(来自类(的函数(作为参数类型(。
哪种解决方案适合你取决于你想做什么。