Min*_*lys 3 kotlin kotlin-generics kotlin-reified-type-parameters
假设我有以下代码:
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 {}
Run Code Online (Sandbox Code Playgroud)
我这样调用该函数:
val appleJuice : AppleJuice = makeJuice(AppleJuice::class.java, Apple())
Run Code Online (Sandbox Code Playgroud)
但是,我不想传递类对象,而是希望将其AppleJuice作为类型传递:
val appleJuice : AppleJuice = makeJuice<AppleJuice>(Apple())
Run Code Online (Sandbox Code Playgroud)
我重构了我的功能以内联reified:
inline fun <F : Fruit, reified J : Juice<F>> makeJuice(fruit : F) : J {}
Run Code Online (Sandbox Code Playgroud)
但是现在我必须指定两种类型:
val appleJuice : AppleJuice = makeJuice<Apple, AppleJuice>(Apple())
Run Code Online (Sandbox Code Playgroud)
从理论上讲,Apple不需要类型,因为它已经从AppleJuice类型中得知。是否有可能摆脱传递不必要的类型而仅传递那些作为as生成的类型reified?
我在解决方案中看到的主要问题是,您要在makeJuice-method 上请求2个泛型类型。双方F并J需要被赋予的功能。尽管对您(以及任何使用该方法的人)很明显,但是我认为在运行时擦除通用类型时可能并不那么明显(但这在这里主要是猜测)。
如果您不介意所传递的水果与您期望的果汁的亚型不完全匹配,那么以下内容可能适合您:
inline fun <reified J : Juice<out Fruit>> makeJuice(fruit : Fruit) : J = TODO()
Run Code Online (Sandbox Code Playgroud)
但是,如果要确保AppleJuice只能使用Apples 构造,那么我只能想到类似于以下的解决方案:
makeJuice在Fruit类中添加,例如
abstract class Fruit {
abstract fun makeJuice() : Juice<out Fruit>
}
// and subclasses:
class Apple : Fruit() {
override fun makeJuice(): AppleJuice = TODO()
}
Run Code Online (Sandbox Code Playgroud)在类中添加makeJuice(/ makeFrom?)Juice,例如
open class Juice<T : Fruit> {
fun makeFrom(fruit : T) { TODO() }
}
Run Code Online (Sandbox Code Playgroud)添加任何其他中间对象,以便您一次不需要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)
Run Code Online (Sandbox Code Playgroud)
并用
using(Apple()).makeJuice<AppleJuice>()
Run Code Online (Sandbox Code Playgroud)使用扩展功能的上述变体,例如
inline fun <reified J : Juice<out Apple>> Apple.makeJuice() : J = TODO()
Run Code Online (Sandbox Code Playgroud)
但您需要为所有类型指定它。不幸的是,以下内容不起作用:
inline fun <F : Fruit, reified J : Juice<F>> F.makeJuice() : J = TODO()
Run Code Online (Sandbox Code Playgroud)
因为我们又遇到了同样的问题...,需要指定<Apple, AppleJuice>。
但也许这些都不是您希望得到的。因此,如果您希望拥有一个可以处理所有问题的方法,则第三个变体可能是您的最佳选择(即使它使用包装器)。
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |