为什么我的通用 StatefulWidget class 在运行时会出现 TypeError?
Why am I getting TypeError at runtime with my generic StatefulWidget class?
我有一个具有 Function
回调的通用 StatefulWidget
class。当我尝试调用该回调时,我得到一个运行时 TypeError
:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _TypeError was thrown building MyStatefulWidget<int>(dirty, state:
MyState<int>#cacb3):
type '(int) => Widget' is not a subtype of type '(dynamic) => Widget'
The relevant error-causing widget was:
MyStatefulWidget<int>
MyStatefulWidget:file:///path/to/my_flutter_project/lib/main.dart:11:13
When the exception was thrown, this was the stack:
#0 MyState.build (package:my_flutter_project/main.dart:33:19)
可重现的例子:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
Widget f(int n) => Text('$n');
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyStatefulWidget<int>(callback: foo, value: 42),
);
}
}
class MyStatefulWidget<T> extends StatefulWidget {
final Widget Function(T) callback;
final T value;
const MyStatefulWidget({
required this.callback,
required this.value,
Key? key,
}) : super(key: key);
@override
MyState<T> createState() => MyState<T>();
}
class MyState<T> extends State<MyStatefulWidget> {
@override
Widget build(BuildContext context) {
return widget.callback(widget.value);
}
}
我已经尝试将 MyStatefulWidget
显式构造为 MyStatefulWidget<int>
,但这没有帮助。 Widget Function(dynamic)
类型来自哪里?
MyState createState() => MyState();
省略了类型参数,所以它 returns 一个 MyState
,它是 shorthand for MyState<dynamic>
.
此外,MyState<T> extends State<MyStatefulWidget>
对于 ... extends State<MyStatefulWidget<dynamic>>
是 shorthand, 而不是 ... extends State<MyStatefulWidget<T>>
的 。
MyState<T>
继承的 widget
成员的静态类型因此将为 MyStatefulWidget<dynamic>
,而 widget.callback
的静态类型将为 Widget Function(dynamic)
.在运行时,关联的 MyStatefulWidget
对象具有对 f
的引用(一个 Widget Function(int)
。但是,不能将其视为 Widget Function(dynamic)
(如 MyState<T>
所期望的那样)因为 f
不能接受所有 dynamic
参数,所以你在运行时得到一个 TypeError
。
底线
如果您有泛型 StatefulWidget
,则必须在 StatefulWidget
引用其 State
class 或 State
指的是它的StatefulWidget
class。常见错误是:
- 忽略
createState
中的类型参数。
- 在为相应的
State
声明继承时忽略类型参数 class。
所以:
class MyStatefulWidget<T> extends StatefulWidget {
...
MyState createState() => MyState(); // WRONG
}
class MyState<T> extends State<MyStatefulWidget> { // WRONG
...
}
应该是:
class MyStatefulWidget<T> extends StatefulWidget {
...
MyState<T> createState() => MyState<T>();
}
class MyState<T> extends State<MyStatefulWidget<T>>
...
}
strict_raw_types
analysis option 有时可以帮助捕获此类错误,尽管当前的实现似乎只检查隐式 dynamic
类型参数并且似乎没有捕获类型参数受限制的情况(比如如果你有 MyStatefulWidget<T extends num>
).
我有一个具有 Function
回调的通用 StatefulWidget
class。当我尝试调用该回调时,我得到一个运行时 TypeError
:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _TypeError was thrown building MyStatefulWidget<int>(dirty, state:
MyState<int>#cacb3):
type '(int) => Widget' is not a subtype of type '(dynamic) => Widget'
The relevant error-causing widget was:
MyStatefulWidget<int>
MyStatefulWidget:file:///path/to/my_flutter_project/lib/main.dart:11:13
When the exception was thrown, this was the stack:
#0 MyState.build (package:my_flutter_project/main.dart:33:19)
可重现的例子:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
Widget f(int n) => Text('$n');
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyStatefulWidget<int>(callback: foo, value: 42),
);
}
}
class MyStatefulWidget<T> extends StatefulWidget {
final Widget Function(T) callback;
final T value;
const MyStatefulWidget({
required this.callback,
required this.value,
Key? key,
}) : super(key: key);
@override
MyState<T> createState() => MyState<T>();
}
class MyState<T> extends State<MyStatefulWidget> {
@override
Widget build(BuildContext context) {
return widget.callback(widget.value);
}
}
我已经尝试将 MyStatefulWidget
显式构造为 MyStatefulWidget<int>
,但这没有帮助。 Widget Function(dynamic)
类型来自哪里?
MyState createState() => MyState();
省略了类型参数,所以它 returns 一个 MyState
,它是 shorthand for MyState<dynamic>
.
此外,MyState<T> extends State<MyStatefulWidget>
对于 ... extends State<MyStatefulWidget<dynamic>>
是 shorthand, 而不是 ... extends State<MyStatefulWidget<T>>
的 。
MyState<T>
继承的 widget
成员的静态类型因此将为 MyStatefulWidget<dynamic>
,而 widget.callback
的静态类型将为 Widget Function(dynamic)
.在运行时,关联的 MyStatefulWidget
对象具有对 f
的引用(一个 Widget Function(int)
。但是,不能将其视为 Widget Function(dynamic)
(如 MyState<T>
所期望的那样)因为 f
不能接受所有 dynamic
参数,所以你在运行时得到一个 TypeError
。
底线
如果您有泛型 StatefulWidget
,则必须在 StatefulWidget
引用其 State
class 或 State
指的是它的StatefulWidget
class。常见错误是:
- 忽略
createState
中的类型参数。 - 在为相应的
State
声明继承时忽略类型参数 class。
所以:
class MyStatefulWidget<T> extends StatefulWidget {
...
MyState createState() => MyState(); // WRONG
}
class MyState<T> extends State<MyStatefulWidget> { // WRONG
...
}
应该是:
class MyStatefulWidget<T> extends StatefulWidget {
...
MyState<T> createState() => MyState<T>();
}
class MyState<T> extends State<MyStatefulWidget<T>>
...
}
strict_raw_types
analysis option 有时可以帮助捕获此类错误,尽管当前的实现似乎只检查隐式 dynamic
类型参数并且似乎没有捕获类型参数受限制的情况(比如如果你有 MyStatefulWidget<T extends num>
).