Kotlin中的代数数据类型

22

我正在尝试学习如何在Kotlin中使用代数数据类型,因此我尝试以以下方式实现基本的二叉树类型。

sealed class Tree<T>{
  class Node<T>(val left: Tree<T>, val right: Tree<T>): Tree<T>()
  class Leaf<T>(val value: T): Tree<T>()
}

这很好,让我构建以下树形结构:
val myTree1: Tree<Int> = Node(Leaf(4), Leaf(2))

然而,我也希望有一个“空”类型,以便我可以表达以下内容:
val myTree1: Tree<Int> = Node(Node(Leaf(4), Leaf(3)), Empty)

我尝试了以下方法:
sealed class Tree<T>{
  class Node<T>(val left: Tree<T>, val right: Tree<T>): Tree<T>()
  class Leaf<T>(val value: T): Tree<T>()
  object Empty: Tree()
}

尽管我收到了“Type argument is expected at object Empty: Tree()”这个错误,但实际上这是相当合理的。
我尝试过。
object Empty: Tree<T>()

但是结果出现了“未解决的引用:T”。作为最后一招,我尝试编写:

object Empty<T>: Tree<T>()

但编译器会提示“对象不允许使用类型参数”

在Kotlin中有没有一种表达方式?Empty应该是一个单例,所以它应该是一个对象。通过将其设置为类,可以解决编译器问题,但然后我必须在其后加上括号,如=> Empty()。此外,它会创建不必要的对象,而它实际上应该是一个单例值。

我会很感谢任何关于这个问题的帮助。 :)

1个回答

29

首先,您需要将T设置为out参数。然后,您可以使用Nothing作为Empty的类型参数。

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

Nothing 是 Kotlin 中的一个特殊类型,它不能有实例,并且是所有其他类型的子类型。因此我会说它在 Kotlin 类型层次结构中与 Any 相反。


3
它有效了,谢谢!同时,我也学到了一些关于“无”的东西。 :) - pjozsef
你不需要在这里使用“out” - 它可以不用。请澄清一下。 - voddan
4
@voddan 如果你移除 out,就无法创建一个包含 LeafEmptyNode - Michael
2
如果我需要T成为Comparable(我在考虑BST),该怎么办? 声明 sealed class Tree<out T : Comparable<T>> {..} 会出现错误“Kotlin:将类型参数T声明为“out”,但在类型Comparable <T>中处于“in”位置”。 - David Soroko
@David Soroko:你有找到任何可行的实现Comparable<T>例子的解决方案吗? - Joerg
不是一个令人满意的解决方案。一种方法是放弃拥有单例对象Empty,移除out并使用class Empty<T> : Tree<T>()。然后你可以接受多个Empty实例或手动管理单个特定类型的实例。 - David Soroko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接