Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Scala中为树代数数据类型的叶子调用构造函数?_Scala_Generics_Constructor_Abstract Data Type_Algebraic Data Types - Fatal编程技术网

如何在Scala中为树代数数据类型的叶子调用构造函数?

如何在Scala中为树代数数据类型的叶子调用构造函数?,scala,generics,constructor,abstract-data-type,algebraic-data-types,Scala,Generics,Constructor,Abstract Data Type,Algebraic Data Types,我正在创建一些基本的抽象数据类型和算法来复习我的CS基础知识,并在此过程中学习Scala。我的BinarySearchTree数据类型遇到了问题,它是一个更抽象的BinaryTree的实现: abstract class BinaryTree[T](stored_value: T) { var contents = stored_value var l: this.type = _ var r: this.type = _ ... } class BinarySearchTr

我正在创建一些基本的抽象数据类型和算法来复习我的CS基础知识,并在此过程中学习Scala。我的BinarySearchTree数据类型遇到了问题,它是一个更抽象的BinaryTree的实现:

abstract class BinaryTree[T](stored_value: T) { 
  var contents = stored_value
  var l: this.type = _
  var r: this.type = _
  ...
}

class BinarySearchTree[T <: Ordered[T]](stored_value: T) extends BinaryTree(stored_value) {  
  def insert(newval: T) {
    if (newval <= contents) {
      if (l == null) {
        throw new NotDefinedError("Still trying to work around type erasure.")
      } else {
        l.insert(newval)
      }
    } else {
      if (r == null) {
        throw new NotDefinedError("Still trying to work around type erasure.")
      } else {
        r.insert(newval)
      }
    }
  }
或:


我是否需要在BinarySearchTree的定义中使用不同的类型覆盖l和r?或者在我给构造函数附加新值时调用不同类型的构造函数?或者其他选项?

我会这样定义它:

class BinaryTree[T](
  val item: T,
  val left: Option[BinaryTree[T]] = None,
  val right: Option[BinaryTree[T]] = None) {

  override def toString() = "Tree(%s,%s,%s)".format(item,left,right)
}

class BinarySearchTree[T: Ordering](
  override val item: T,
  override val left: Option[BinarySearchTree[T]] = None,
  override val right: Option[BinarySearchTree[T]] = None) extends BinaryTree[T](item, left, right) {

  def insert(newval: T): BinarySearchTree[T] = {
    val (newLeft, newRight) =
      if (implicitly[Ordering[T]].lteq(newval, item))
        (insertSubtree(newval, left), right)
      else
        (left, insertSubtree(newval, right))
    new BinarySearchTree(item, newLeft, newRight)
  }

  private def insertSubtree(newval: T, subtree: Option[BinarySearchTree[T]]) =
    Option(subtree
      .map(_.insert(newval))
      .getOrElse(new BinarySearchTree(newval, None, None)))
}
有一些基本的东西我已经改成更像Scala:

  • 使用所有
    val
    字段使结构不可变。让
    insert
    返回一个新的修改过的树。尽可能多地保留旧(不可变)树以避免浪费内存
  • 通过使用
    选项来避免使用
    null
    。因此,
    子树是
    选项[Binary(Search)Tree[T]]
    ,明确表示它们可能存在,也可能不存在
  • 使用子树上的
    映射
    ,因为它是一个
    选项
    insertSubtree
    中的代码基本上是说“如果子树存在,请插入其中。否则,请获取一个新树。”
下面是它的工作原理:

scala> var t = new BinarySearchTree(5, None, None)
t: BinarySearchTree[Int] = Tree(5,None,None)

scala> t = t.insert(3)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,None)),None)

scala> t = t.insert(4)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,Some(Tree(4,None,None)))),None)

scala> t = t.insert(7)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,Some(Tree(4,None,None)))),Some(Tree(7,None,None)))

我同意@dhg的建议,即探索不可变的树数据结构作为当前方向的替代方案。然而,如果一棵可变的树是你真正需要的,那么请继续阅读

您眼前的问题是
this.type
BinaryTree[T]
的定义中并不是您认为它的意思。它实际上是封闭实例的单例类型,即
this
所居住的类型。这里有一个例子说明

scala> class Foo { def self : this.type = this /* OK */ }
defined class Foo

scala> class Bar { def self : this.type = new Bar /* Does not compile */ }
<console>:7: error: type mismatch;
 found   : Bar
 required: Bar.this.type
       class Bar { def self : this.type = new Bar /* Does not compile */ }
                                          ^

谢谢这两个答案都提供了大量的信息,但这一个更直接地抓住了我的意图。我一直在反复考虑是否接受你或另一个答案。迈尔斯通过讨论如何细化派生类中的子树类型,找到了问题的核心,但这个答案对于让我了解一些更好的Scala习惯用法非常有帮助。
scala> var t = new BinarySearchTree(5, None, None)
t: BinarySearchTree[Int] = Tree(5,None,None)

scala> t = t.insert(3)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,None)),None)

scala> t = t.insert(4)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,Some(Tree(4,None,None)))),None)

scala> t = t.insert(7)
t: BinarySearchTree[Int] = Tree(5,Some(Tree(3,None,Some(Tree(4,None,None)))),Some(Tree(7,None,None)))
scala> class Foo { def self : this.type = this /* OK */ }
defined class Foo

scala> class Bar { def self : this.type = new Bar /* Does not compile */ }
<console>:7: error: type mismatch;
 found   : Bar
 required: Bar.this.type
       class Bar { def self : this.type = new Bar /* Does not compile */ }
                                          ^
abstract class BinaryTree[T] {
  type Self <: BinaryTree[T]
  var contents : T
  var l: Self = _
  var r: Self = _
}

class BinarySearchTree[T <: Ordered[T]](stored_value : T) extends BinaryTree[T] {
  type Self = BinarySearchTree[T]
    var contents = stored_value
    def insert(newval: T) {
      if (newval <= contents) {
        if (l == null) {
          new BinarySearchTree(newval)
        } else {
          l.insert(newval)
        }
      } else {
        if (r == null) {
          new BinarySearchTree(newval)
        } else {
          r.insert(newval)
        }
      }
  }
}