为什么 lambda 函数参数的类型在 kotlin 中带星号的泛型类型上是 Nothing?
why lambda function parameter's type is Nothing on generic type with asterisk in kotlin?
当我调用一些 api 时,我希望使用带有通用参数的多个回调。
所以我定义了 CallBackData class
class CallBackData<T>(val func: (T?) -> Boolean, val params: T?)
它不是数据 class。因为它超级 class 其他回调。
并且我为多个回调定义了 Array> 变量。
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
但是当我调用 func 时,它说错误
Type mismatch.
Required: Nothing?
Found: Any?
我不明白。为什么? it.params 类型 T 是否与 it.func(param(T)) 相同?正确的?为什么没有类型?为什么不一样?
这是完整代码
fun start(){
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
我试着转换成这样(使用 out 关键字),但同样失败。(Lambda 的参数类型是 Nothing?)
fun start(){
val callbackDts : Array<CallBackData<out Any?>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<out Any?>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
期待您的回复。谢谢!
你可以定义一个函数
fun <T> CallBackData<T>.call() = func(params)
然后callApi
可以改成:
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{ it.call() }
}
然后 Kotlin 没有问题推断 func
和 params
的类型匹配每个 CallBackData
.
不幸的是,一旦您将 CallbackData<T>
投影到 CallbackData<*>
,T
的类型信息就消失了。不再知道 it.func
采用与 it.params
.
相同的类型
但是您确实知道它们在 CallBackData
class 本身是同一类型,不是吗?所以你可以只添加一个 call
方法
class CallBackData<T>(val func : (T?) -> Boolean, var params: T?) {
fun call() = func(params)
}
和
callbacks.forEach{
it.call()
}
或者您可以重载 invoke
运算符:
operator fun invoke() = func(params)
然后您就可以直接it()
。
即使您无法控制CallBackData
,您仍然可以添加扩展功能:
operator fun <T> CallBackData<T>.invoke() = func(params)
添加到其他答案:如果这是您定义 CallBackData
的唯一原因,那么您真的不需要这个 class。 Kotlin 已经支持闭包,所以我们不需要单独拦截函数和参数:
fun start(){
val callbackDts = arrayOf<() -> Unit>(
{ sampleCallback1(SomeClass(1)) },
{ sampleCallback2("hello") },
{ sampleCallback3(-1) },
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<() -> Unit>){
callbacks.forEach{
it()
}
}
当我调用一些 api 时,我希望使用带有通用参数的多个回调。
所以我定义了 CallBackData class
class CallBackData<T>(val func: (T?) -> Boolean, val params: T?)
它不是数据 class。因为它超级 class 其他回调。
并且我为多个回调定义了 Array
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
但是当我调用 func 时,它说错误
Type mismatch.
Required: Nothing?
Found: Any?
我不明白。为什么? it.params 类型 T 是否与 it.func(param(T)) 相同?正确的?为什么没有类型?为什么不一样?
这是完整代码
fun start(){
val callbackDts : Array<CallBackData<*>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
我试着转换成这样(使用 out 关键字),但同样失败。(Lambda 的参数类型是 Nothing?)
fun start(){
val callbackDts : Array<CallBackData<out Any?>> = arrayOf(
CallBackData(::sampleCallback1, SomeClass(1)),
CallBackData(::sampleCallback2, "hello"),
CallBackData(::sampleCallback3, -1),
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<CallBackData<out Any?>>){
callbacks.forEach{
it.func(it.params)
}
}
fun sampleCallback1(params: SomeClass?) : Boolean {
println("sampleCallback1 ${params.toString()}")
return true
}
fun sampleCallback2(params: String?) : Boolean {
println("sampleCallback2 $params")
return true
}
fun sampleCallback3(params: Int?) : Boolean {
println("sampleCallback3 $params")
return true
}
data class SomeClass(val i:Int)
class CallBackData<T>(val func : (T?) -> Boolean, val params: T?)
期待您的回复。谢谢!
你可以定义一个函数
fun <T> CallBackData<T>.call() = func(params)
然后callApi
可以改成:
fun callApi(callbacks : Array<CallBackData<*>>){
callbacks.forEach{ it.call() }
}
然后 Kotlin 没有问题推断 func
和 params
的类型匹配每个 CallBackData
.
不幸的是,一旦您将 CallbackData<T>
投影到 CallbackData<*>
,T
的类型信息就消失了。不再知道 it.func
采用与 it.params
.
但是您确实知道它们在 CallBackData
class 本身是同一类型,不是吗?所以你可以只添加一个 call
方法
class CallBackData<T>(val func : (T?) -> Boolean, var params: T?) {
fun call() = func(params)
}
和
callbacks.forEach{
it.call()
}
或者您可以重载 invoke
运算符:
operator fun invoke() = func(params)
然后您就可以直接it()
。
即使您无法控制CallBackData
,您仍然可以添加扩展功能:
operator fun <T> CallBackData<T>.invoke() = func(params)
添加到其他答案:如果这是您定义 CallBackData
的唯一原因,那么您真的不需要这个 class。 Kotlin 已经支持闭包,所以我们不需要单独拦截函数和参数:
fun start(){
val callbackDts = arrayOf<() -> Unit>(
{ sampleCallback1(SomeClass(1)) },
{ sampleCallback2("hello") },
{ sampleCallback3(-1) },
)
callApi(callbackDts)
}
fun callApi(callbacks : Array<() -> Unit>){
callbacks.forEach{
it()
}
}