给出以下Kotlin代码:
class Foo<T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
为什么会出现以下错误:
Type mismatch. Required: Foo<String?> Found: Foo<String>
如果我将扩展功能中的?
删除为Foo<T>.transform
,则会收到以下错误消息:
Type mismatch. Required: Foo<Int> Found: Foo<Int?>
我可以理解第二个错误,因为您无法将Int?
分配给Int
,但是第一个没有意义,因为您可以将String
分配给{{1} }
编辑:
我将String?
修改为class Foo<T>
,这对我有用,因为值class Foo<out T>
仅在初始分配后才能读取。使用此选项,我不需要在t
的调用站点上定义类型参数。
我发现我认为还有一点混乱(并且不确定为什么会有所不同),这是在扩展函数中添加第三个类型参数,如下所示:
transform
另一方面,我的呼叫站点有点奇怪。看上面的代码,fun <T : Any, U : T?, R : Any> Foo<U>.transform(transformer : (T) -> R) : Foo<R?>
的调用绝不能包含类型参数,但是foo.transform
的调用必不可少包含类型参数去工作。
此选项允许稍后将值bar.transform<Int, Int?, IntRange>
设置为t
而不是var
来设置值val
。但这也会删除t
函数中transform
上的智能转换。尽管如果您不担心比赛条件,可以通过!!
来解决问题;如果您担心比赛条件,(可以通过一些额外的努力)可以使用?:
或?.
来解决问题。
答案 0 :(得分:0)
您可以将Foo<T>
类更改为不是不变的(请参见https://kotlinlang.org/docs/reference/generics.html):
class Foo<out T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
out T
精确地指定了您想要的行为。
答案 1 :(得分:0)
由于您在构造函数中将属性t
指定为T?
,因此无需将Foo<T?>
指定为接收者,将Foo<R?>
指定为返回类型。而是使用Foo<T>
和Foo<R>
,它将起作用。
class Foo<T>(val t : T?)
fun <T: Any, R: Any> Foo<T>.transform(transformer : (T) -> R) : Foo<R> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform { t -> t.length }
val baz = bar.transform { t -> t..(t + 1) }
}
注意:您无需指定要转换的通用类型,因为可以推断出它们(至少在此示例中如此)。