假设我有以下代码:
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
制成的那些类型?
答案 0 :(得分:5)
我看到的解决方案的主要问题是,您在makeJuice
方法中要求两种通用类型。 F
和J
都需要赋予该功能。尽管对您(以及任何使用此方法的人)都很明显,但我认为在运行时擦除通用类型可能并不那么明显(但这在这里主要是猜测)。
如果您不介意所传递的水果与您期望的果汁的亚型不完全匹配,那么以下内容可能适合您:
inline fun <reified J : Juice<out Fruit>> makeJuice(fruit : Fruit) : J = TODO()
但是,如果您想确保AppleJuice
只能用Apple
来构造,那么我只能想到类似于以下的解决方案:
将makeJuice
添加到Fruit
类中,例如
abstract class Fruit {
abstract fun makeJuice() : Juice<out Fruit>
}
// and subclasses:
class Apple : Fruit() {
override fun makeJuice(): AppleJuice = TODO()
}
将makeJuice
(/ makeFrom
?)添加到Juice
类中,例如
open class Juice<T : Fruit> {
fun makeFrom(fruit : T) { TODO() }
}
添加任何其他中间对象,以使您一次不需要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>()
上述变量使用扩展功能,例如
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>
。
但也许这些都不是您希望得到的。 因此,如果您希望拥有一个可以处理所有问题的方法,那么第三个变体可能是您的最佳选择(即使它使用包装器也是如此)。