实施Kotlin标准库扩展功能let
:
extension KtStd<T, R> on T {
R let(R f(T it)) => f(this);
}
并编写一个CLI和计算器(无法简化问题),期望:
input: 1 2 3 4 5 6 7 8 9
output: 45
input: apple 1.2 banana 3.4
output: 4.6
然后输入代码:
main() {
stdin.readLineSync(encoding: Encoding.getByName('utf-8')).split(" ")
.map((s) => double.tryParse(s)).where((e) => e != null).fold(0, (acc, i) => acc + i)
.let((d) => d % 1 == 0 ? d.toInt() : d)
.let((it) => print(it));
}
输入1 2 3
时收到错误消息:
Unhandled exception:
NoSuchMethodError: Class 'double' has no instance method 'let'.
Receiver: 6.0
Tried calling: let(Closure: (dynamic) => dynamic)
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 main (file:xxx.dart:xx:xx)
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
此外,如果我将fold
函数更改为reduce
,则输入相同,得到错误消息:
Unhandled exception:
NoSuchMethodError: Class 'int' has no instance method 'let'.
Receiver: 6
Tried calling: let(Closure: (dynamic) => void)
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 main (file:xxx.dart:xx:xx)
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
飞镖版本是:
Dart VM version: 2.8.2 (stable) (Mon May 11 15:06:42 2020 +0200) on "windows_x64"
为什么我收到这些错误消息?我该怎么解决?
答案 0 :(得分:2)
Dart扩展名是静态。它们是语法糖,适用于编译时已知的类型。这意味着扩展不能在运行时确定类型的dynamic
值上使用。
您的长链表达式最终可能会使用dynamic
类型,而这些类型可能不在您所期望的位置。一个问题是,当您执行.fold(0, (acc, i) => acc + i)
时,不会推导出回调的参数和返回类型。 (请参见https://github.com/dart-lang/language/issues/731。)因此acc
和返回类型被假定为dynamic
类型。
您可以通过为fold
:.fold<double>(...)
明确指定类型来解决此问题。
在代码的编辑版本中,您引入了第二个问题:
extension KtStd<T, R> on T {
R let(R f(T it)) => f(this);
}
您打算让KtStd<T, R>
依靠let
来约束R
,但这是倒退的。在未首先将let
扩展为KtStd<T, R>
的情况下,T
不是合法电话。 R
因此不受约束,并假定为dynamic
。然后,这也迫使let
也返回dynamic
。
如果可能,我建议恢复到您的较早版本,其中let
在R
上是单独通用的:
extension KtStd<T> on T {
R let<R>(R f(T it)) => f(this);
}
通过修改analysis_options.yaml
文件并进行设置,您可以在分析过程中更轻松地识别此类错误:
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
language:
strict-raw-types: true
答案 1 :(得分:0)
如果您要坚持使用泛型,这也可以:
extension KtStd<T> on T {
R let<R>(R Function(T) function) => function(this);
}
您的扩展方法也可以用这种方式编写(请参见lint):
extension KtStd<T> on T {
R let<R>(R Function(dynamic) f) => f(this);
}
我实际上无法解释为什么,但是您需要指定功能参数的类型以使其正常工作
答案 2 :(得分:-1)
尝试对象
extension KtStd on Object {
Object let(Object f(it)) => f(this);
}
void main() {
"12"
.let((it) => it.toString() + "3")
.let((it) => int.parse(it) + 1)
.let((it) => print(it)); //124
}