Kotlin:创建泛型类的子类继承函数并限制可用的输出类型

时间:2018-02-04 18:19:38

标签: generics inheritance kotlin generic-variance

我有以下Kotlin类实现类似于Collections接口的东西或包含多个元素的集合。

abstract class MyCollection<C: MyCollection<C>> {
    abstract fun contains(e: Member<C>): Member<CollectionOfBooleanValues>
    //Function that determines if a Member<C> is present in this collection.
    // Maps to a collection of boolean values (True, False and Unsure)

    abstract fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): E
    //Function that return a collection of the element that are created from
    //a mapping of this collection through a function f.
    //This could for example be the owners of the things of this collection, provided we
    //have a Persons class extends MyCollection. Or a collection of all colors of the things in this collection.
}

abstract class BigCollection<C: BigCollection<C>>: MyCollection<C>() {
    override fun contains(e: Member<C>): Member<CollectionOfBooleanValues> = Unsure

    abstract override fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): E
}

abstract class SmallCollection<C: SmallCollection<C>>(val choices: List<Member<C>>): BigCollection<C>() {
    override fun contains(e: Member<C>): Member<CollectionOfBooleanValues> =
        if(choices.contains(e))
            True
        else
            False
}

abstract class Persons<D: Persons<D>>: MyCollection<D>() {
    override fun contains(e: Member<D>): Member<CollectionOfBooleanValues> {
        return True
    }
}

abstract class Member<D: MyCollection<D>>(sym: String, val collectionType: D) {
}

object CollectionOfBooleanValues: SmallCollection<CollectionOfBooleanValues>(choices = listOf(True, False, Unsure)){
    override fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<CollectionOfBooleanValues>) -> Member<E>): E =
            throw RuntimeException("Not implemented");
}

object True: Member<CollectionOfBooleanValues>("true", CollectionOfBooleanValues)
object False: Member<CollectionOfBooleanValues>("false", CollectionOfBooleanValues)
object Unsure: Member<CollectionOfBooleanValues>("unsure", CollectionOfBooleanValues)

因此,MyCollection的一个子类的实例描述了某种类的集合和类的实例&lt; C>描述该集合的特定成员。 子类BigCollection和SmallCollection确定我们拥有的集合大小。我的想法是在这里添加更多内容,具体取决于集合的使用难度。

可以想象以下示例

Red可以是Member&lt;类型的实例/对象。颜色&gt;

人可以是SmallCollection类型的子类型&lt;人员&gt;

Color可以是BigCollection类型的子类型&lt;颜色&gt;并且基本上是无限的。这意味着,例如,函数包含(Member&lt; Color&gt;)永远不会返回false,只有在发现它时才会出现Unsure或True,并在特定超时后抛出异常。

这样你就可以对我尝试做的事情有一个基本的了解。

注意JVM的类型擦除如何强制我使用递归泛型,如果我想访问类型MyCollection&lt; C>在编译时和运行时。

我们可以看到它相当安全。我们知道mapToOtherDomain将返回一个E,它是MyCollection的子类型&lt; D>并且它将与函数中的E相同类型(成员&lt; C&gt;) - &gt;构件&LT; E&gt;)我们投入。

现在,如果MyCollection的子类可以覆盖函数mapToOtherCollection,那么整洁将是如此,以便大小反映在函数的静态签名中。函数f是一对一的映射,所以如果我们将类型A的smallCollection映射到B,我希望输出为B的smallCollection。

我觉得这应该是可能的,特别是因为它几乎可以在Java中使用,而且Kotlin应该是Java的通用类型系统的扩展。我不能让它工作。我希望它覆盖,但仍然限制返回类型(因此也限制输入类型)

我已经玩过这样的方法签名:

abstract class BigCollection<C: BigCollection<C>>: MyCollection<C>() {
    abstract override fun <E: BigCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): E
}

给出了编译器错误,它没有覆盖以前的方法,并且像这样

abstract class MyCollection<C: MyCollection<C>> {
    abstract fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): MyCollection<E>
}

abstract class BigCollection<C: BigCollection<C>>: MyCollection<C>() {
    abstract override fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): BigCollection<E>
}

表示Type参数超出范围。

如何限制输入/输出类型以更好地匹配此示例中泛型类的子类?如果编译器知道BigCollection中的contains()的输出将是静态的而不是动态的,那么它也会很简洁。

由于

1 个答案:

答案 0 :(得分:0)

很难说这是否有帮助,但是您至少可以将其视为解决方法:

abstract class BigCollection<C: BigCollection<C>>: MyCollection<C>() {
    override fun <E: MyCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): MyCollection<E> {
        return this.mapToOtherCollection(f)
    }

    abstract fun <E: BigCollection<E>> mapToOtherCollection(f: (Member<C>) -> Member<E>): BigCollection<E>
}

这里发生的事情类似于JVM“桥接”方法:我们创建一个具有更具体签名的方法并将其委托给它。