3

假设我有以下代码:

open class Fruit
class Apple : Fruit()
open class Juice<T : Fruit>
class AppleJuice : Juice<Apple>()

fun <F : Fruit, J : Juice<F>> makeJuice(juiceClass : Class<J>, fruit : F) : J {}

我这样调用函数:

val appleJuice : AppleJuice = makeJuice(AppleJuice::class.java, Apple())

但是我不想传递一个类对象,而是AppleJuice作为一个类型传递:

val appleJuice : AppleJuice = makeJuice<AppleJuice>(Apple())

我已将我的函数重构为内联reified

inline fun <F : Fruit, reified J : Juice<F>> makeJuice(fruit : F) : J {}

但现在我必须指定两种类型:

val appleJuice : AppleJuice = makeJuice<Apple, AppleJuice>(Apple())

理论上,Apple不应该需要类型,因为它已经从AppleJuice类型中知道了。是否有可能摆脱传递不必要的类型而只传递那些作为reified

4

1 回答 1

6

我在您的解决方案中看到的主要问题是,您在makeJuice-method 上要求使用 2 种泛型类型。两者都F需要J赋予函数。虽然这对您(以及任何查看该方法的人)来说很明显,但我认为在运行时擦除泛型类型时可能并不那么明显(但现在主要是这里的猜测)。

如果您不介意您传递的水果与您期望的果汁的亚型不匹配,那么以下可能适合您:

inline fun <reified J : Juice<out Fruit>> makeJuice(fruit : Fruit) : J = TODO()

但是,如果您想确保AppleJuice只能用Apples 构造,那么我只能想到类似于以下的解决方案:

  1. 添加makeJuiceFruit类中,例如

    abstract class Fruit {
      abstract fun makeJuice() : Juice<out Fruit>
    }
    // and subclasses:
    class Apple : Fruit() {
      override fun makeJuice(): AppleJuice = TODO()
    }
    
  2. 在类中添加makeJuice(/ makeFrom?) Juice,例如

    open class Juice<T : Fruit> {
      fun makeFrom(fruit : T) { TODO() }
    }
    
  3. 添加任何其他中间对象,这样您就不需要一次使用 2 个泛型类型,例如

    class JuiceMaker<F : Fruit>(val fruit : F) {
      inline fun <reified J : Juice<F>> makeJuice() : J = TODO()
    }
    fun <F : Fruit> using(fruit : F) = JuiceMaker(fruit)
    

    并用

    using(Apple()).makeJuice<AppleJuice>()
    
  4. 以上使用扩展功能的变体,例如

    inline fun <reified J : Juice<out Apple>> Apple.makeJuice() : J = TODO()
    

    但您需要为所有类型指定它。不幸的是,以下内容将不起作用:

    inline fun <F : Fruit, reified J : Juice<F>> F.makeJuice() : J = TODO()
    

    因为我们又遇到了同样的问题......并且需要指定<Apple, AppleJuice>.

但也许这些都不是你希望得到的。因此,如果您想要一个方法来处理这一切,那么第三种变体可能是您的最佳选择(即使它使用包装器)。

于 2018-08-20T11:50:59.710 回答