Kotlin中协议实现可识别的推断类型

时间:2019-01-23 22:08:48

标签: generics kotlin reification inferred-type

我正在尝试创建一个系统,其中协议(或抽象类)的实现可以满足该协议的最低要求,但仍可以访问提供的解决方案随附的独特功能。让我用一个例子来说明:

interface Food
interface Animal {
    val favoriteFood: Food
}

class Banana: Food {
    fun peel() {
        print("Banana peeled")
    }
}

class Monkey: Animal {
    override val favoriteFood: Food = Banana()

    init {
        favoriteFood.peel() // Doesn't work as type is Food, not Banana
    }
}

现在要破解这个问题,我一直在研究泛型和泛型函数,但是我还没有想出能以表达方式起作用的东西。

我应该注意,我的实现必须满足多个要求。我可以通过在协议上使用泛型来完成这项工作。

interface Animal<T: Food, B: Behaviour>

这可以工作,但是由于有多个要求,它很快看起来很荒谬,我觉得我缺少了一些东西。除非在下一个示例中缺少某些内容,否则属性的泛型将不起作用。

// Protocol
val <T> favoriteFood: <T: Food>
// Implementation (ideally, but wouldn't work like that I guess)
override val favoriteFood: Banana = Banana()

然后我的改良方法看上去也不是那么漂亮:

open class Animal {
    // This should ideally be private to prevent incorrect use
    var favoriteFood: Food? = null

    fun registerFavoriteFood(food: Food) {
        favoriteFood = food
    }

    // This probably doesn't even have to be inline+reified
    inline fun <reified  T> getFavoriteFood() : T {
        // Of course we need to validate if favoriteFood matches T 
        return favoriteFood as T
    } 
}

class Monkey: Animal() {
    init {
        registerFavoriteFood(Banana())
        getFavoriteFood<Banana>().peel()
    }
}

在这一点上,我不确定我是否看不到该怎么做或是否不可能。感觉这是有可能的,我想知道是否有人可以为我指出正确的解决方法。

或者也许它甚至与我想做的事情都没有道理,但即使我也想听,因为它对我所设想的设置确实有意义。

谢谢。

在首次回复后进行编辑: 我打算在构建阶段之外也访问favouriteFood。 将可变的favouriteFood转换为val,因为它更适合目标。

1 个答案:

答案 0 :(得分:1)

只要在构造时只尝试访问favoriteFood,这还不错:

class Monkey: Animal {
    override var favoriteFood: Food? // no initializer here

    init {
        val food = Banana()
        favoriteFood = food
        food.peel()
    }
}

如果您将自己限制在init节和其他构造时操作中,那么您尝试做的事情将从根本上被破坏。

val animal: Animal = Monkey()
animal.favoriteFood = Orange() // favoriteFood is a var, so it's publicly modifiable
animal.something() // can't assume favoriteFood is a Banana!

您可以将favoriteFood改成val,这会有所帮助。但是您不能从favoriteFood中的类型之外使Food可变,并尝试限制子类型中favoriteFood的类型。