【问题标题】:How to have multiple upper bounds for the generic type parameter of a function?如何为函数的泛型类型参数设置多个上限?
【发布时间】:2020-12-03 19:02:29
【问题描述】:

有一个抽象类Base和一个接口BaseAction。在我的项目中,AB 都实现了BaseBaseAction

abstract class Base {
    abstract fun doAction()
}

interface BaseAction {

}

class A: Base(), BaseAction {
    override fun doAction() {

    }
}

class B: Base(), BaseAction {
    override fun doAction() {

    }
}

现在我定义了一个抽象类AbstractCommand,里面有一个函数:

abstract class AbstractCommand {
    abstract fun <T> getActions(): List<T> where T: Base, T: BaseAction

    fun doSomething() {
        // Here A and B both are Ok for me.
        getActions<>()
    }

}

如您所见,有两个上限:BaseBaseAction。在函数doSomething中,我想调用getActions,在那个List中,A类和B类都适合我。

我的问题是如何调用getActions

编辑

是的,我可以在 AbstractCommand 类中定义 T,但如果是这样,AbstractCommand 只返回 ListA> 或 ListB>。但是 List 是预期的。

编辑

我的描述是我的错。我必须更多地解释我的问题,并解释让 A 和 B 直接扩展同一个父级是不合适的。

事实上,如上所述,我的问题更复杂。让我举个完整的例子。

abstract class Base {
    abstract fun doAction()
}

interface BuyGiftAction {
    abstract fun buyGift()
}

abstract class A: Base(){
    abstract fun doActionA()
}

abstract class B: Base() {
    abstract fun doActionB()
}

如您所见,A 和 B 都扩展了 Base 类并定义了新的抽象函数。现在 A 的孩子想要实现 BuyGiftAction 而 B 的孩子这样做。

class ChildA: A(), BuyGiftAction {
    override fun doActionA() {
    }

    override fun doAction() {
    }

    override fun buyGift() {
    }
}

class ChildB: B(), BuyGiftAction {
    override fun doActionB() {
    }

    override fun doAction() {
    }

    override fun buyGift() {
    }
}

显然,让AB 都扩展一个名为Parent 的类是非常不合适的,该类扩展Base 并实现BuyGiftAction

abstract class AbstractCommand {
    abstract fun <T> getActionArray(): Array<T> where T: Base, T: BuyGiftAction

    fun doSomething() {
        // Here ChildA and ChildB both are Ok for me.
        getActionArray<>()
    }

}

Try it here!

【问题讨论】:

  • 列表不是有效类型,缺少泛型类型参数。你的意思是List&lt;Any&gt;
  • @WilliMentzel 列表中的项目应该扩展 Base 并实现 BaseAction。
  • @WilliMentzel 所以我很困惑,想知道是否有其他方法可以实现这一点。
  • @WilliMentzel OP 想要一个包含 As 和 B 的异构列表,除非我们指定一个共同的父类型,否则我不确定我们能否拥有它。

标签: kotlin generics


【解决方案1】:

为了使doSomething 使用与getActions 相同的T,您需要将T 设为AbstractCommand 的泛型类型参数:

abstract class AbstractCommand<T> where T: Base, T: BaseAction {
    abstract fun getActions(): List<T>

    fun doSomething() {
        getActions()
    }
}

【讨论】:

  • 但是我不希望 AbstractCommand 只映射 A 或 B。A 和 B 都应该没问题。
  • 如你所见,未来C、D、E即将到来。但是 A B C D E 既扩展了 Base 又实现了 BaseAction。
【解决方案2】:

您定义getActions() 的方式当前意味着您返回一个单一 类型T 的列表,它需要扩展Base 并实现BaseAction。所以要么只在你的列表中As,要么只在Bs,但你不能在这里混合As和Bs。

如果您希望列表中包含异构类型,则必须使 getActions() 返回除 T 之外的其他内容,类似于单个基类。

我认为最简单的方法是让基类Base 实现BaseAction,或者创建一个中间类(例如Action),既扩展Base 又实现BaseAction,并且@ 987654336@ 和 B 可以派生自。


abstract class Action : Base(), BaseAction

class A: Action() {
    override fun doAction() { ... }
}

class B: Action() {
    override fun doAction() { ... }
}
abstract class AbstractCommand {
    abstract fun getActions(): List<Action>

    fun doSomething() {
        // Here A and B both are Ok for me.
        getActions()
    }
}

【讨论】:

  • 我猜这不是关于列表能够同时容纳 A 和 B,我猜他想要的是 doSomething 中的 getActions 使用与他最初称为 getActions 相同的 T。如果他再次使用 T 的另一种类型调用 getActions,那么 doSomething 的 getActions() 应该使用它。这是不可能的。但是如果我错了,OP应该纠正我。
  • @WilliMentzel 如果这确实是 OP 需要的,那么他应该对您的回答感到满意。让我们等待OP的评论澄清。但是我从问题的 EDIT 部分以及他对您的回答的 cmets 中理解了对异构列表的需求。
猜你喜欢
  • 2021-06-27
  • 1970-01-01
  • 2016-09-06
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
  • 2019-03-05
相关资源
最近更新 更多