如何在通用接口中引用实现类

时间:2018-07-16 21:46:17

标签: kotlin

比方说,我想定义一个接口来描述包含相似对象的对象的任何树形结构。一个明显的实现是:

interface HasChildren {
    val children: Sequence<HasChildren>
}

class Branch(val children: Sequence<Branch>) : HasChildren

与此有关的一个或多或少的明显问题是,尽管Branch的子代必须始终是Branch,但是它已经通过接口丢失了,我必须显式地对它们进行类型转换。回来。

有没有一种方法,类似于Swift中的Self

protocol HasChildren {
    let children : Sequence<Self> { get }
}

不丢失实现类的类型?

2 个答案:

答案 0 :(得分:2)

这叫做F-bounded polymorphism(本文是为Scala写的,但这没关系;我找不到我喜欢使用Java或Kotlin的解释,但是概念完全相同):

interface HasChildren<T : HasChildren<T>> {
    val children: Sequence<T>
}

class Branch(override val children: Sequence<Branch>) : HasChildren<Branch>

如果您熟悉C ++,则在这里称为"curiously recurring template pattern"

答案 1 :(得分:1)

我认为您可能想看看sealed class es。使用它们的树看起来像这样:

sealed class Node<out T> {
    class Branch<T>(val left: Node<T>, val right: Node<T>) : Node<T>()
    class Leaf<T>(val value: T) : Node<T>()
    object Empty : Node<Nothing>()
}

sealed class支持使用when进行类型检查:

when(node) {
    is Branch-> {
        // ... 
    }
    is Leaf -> {
        // ... 
    }
    is Empty -> {
        // ...
    }
}

用法:

val tree = Branch(
          Leaf("Foo"),
          Branch(Leaf("baz"), Empty))

official docs也是一个很好的起点。

编辑:AFAIK,如果没有类型转换,您将无法做到这一点。我已经将一个简单的程序与一个hack结合在一起:

object Playground {

    @JvmStatic
    fun main(args: Array<String>) {
        val tree = Branch(
                Leaf("Foo"),
                Branch(Leaf("baz"), Empty))

        // works
        val foo = tree.left.castTo<Node.Leaf<String>>()

        println(foo)

        // oops
        tree.left.castTo<Node.Empty>()
    }

}


sealed class Node<out T> {
    data class Branch<T>(val left: Node<T>, val right: Node<T>) : Node<T>()
    data class Leaf<T>(val value: T) : Node<T>()
    object Empty : Node<Nothing>()
}

inline fun <reified U : Node<Any>> Node<Any>.castTo(): U {
    require(this is U) {
        "Node '${this::class.simpleName}' is not of required type '${U::class.simpleName}'."
    }
    return this as U
}

我真的很想看到一个更强大的解决方案,因为这很丑陋,但是到目前为止我还没有找到更好的解决方案(我有时也会遇到这个问题)。