如何解决类型不匹配的问题必需:Foo <type>,找到的是:Foo <type?>

时间:2019-01-19 01:48:56

标签: kotlin

给出以下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上的智能转换。尽管如果您不担心比赛条件,可以通过!!来解决问题;如果您担心比赛条件,(可以通过一些额外的努力)可以使用?:?.来解决问题。

2 个答案:

答案 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) }
}

注意:您无需指定要转换的通用类型,因为可以推断出它们(至少在此示例中如此)。