【问题标题】:Why doesn't this code compile? Is this really unsafe?为什么这段代码不能编译?这真的不安全吗?
【发布时间】:2012-07-13 13:47:56
【问题描述】:

考虑这个简单的二叉树类型:

abstract class BinaryTree[T] {
  type Repr <: BinaryTree[T]

  def left: Repr
  def value: T
  def right: Repr

  def height: Int

 def add(elem: T): Repr = 
    if ( left.height <= right.height ) copy( left.add( elem ), right)
    else copy( left, right.add(elem))

 def copy( left: Repr, right: Repr ) : Repr
}

abstract class BinarySearchTree[T] extends BinaryTree[T] {
  type Repr <: BinarySearchTree[T]

  def ordering: Ordering[T]

  override def add(elem: T) = 
    if ( ordering.equiv( elem, value ) ) this.asInstanceOf[Repr]
    else if ( ordering.lt(elem, value) ) copy( left.add( elem ), right )
    else copy( left, right.add( elem ) )
}


class ScapegoatTree[T]( val value: T, val left: ScapegoatTree[T], val right: ScapegoatTree[T] )(implicit val ordering: Ordering[T])
  extends BinarySearchTree[T] {

  type Repr = ScapegoatTree[T]

  def add = this /* snip */

  def copy( left: ScapegoatTree[T], right: ScapegoatTree[T] ) = new ScapegoatTree( value, left, right )
}

class BalancedBinaryTree[T]( val value: T, val left: BalancedBinaryTree[T], val right: BalancedBinaryTree[T] )(implicit val ordering: Ordering[T])
  extends BinarySearchTree[T] {

  type Repr = BalancedBinaryTree[T]

  def add = this /* snip */

  def copy( left: BalancedBinaryTree[T], right: BalancedBinaryTree[T] ) = new BalancedBinaryTree( value, left, right )
}

在 Scala-IDE 中使用 Scala 2.9,add 方法无法编译,因为 copy 需要 Reprleft.add(elem)right.add(elem) 返回 Repr#Repr。据我所知,Repr#Repr 必须始终是Repr 的子类型,因此它应该是安全的。我是否没有考虑某些情况,或者这是幸运的是,类型系统阻止你做一些应该工作的事情是罕见的情况之一?

另外,有什么方法可以改变我的类型定义,这样这将是合法的,或者向编译器断言Repr#Repr 必须是Repr 的子类型(我的意思是除了演员表)。我还在习惯 Scala,但我不确定我是否完全理解了类型系统。我确实通过编写一个执行强制转换的隐式方法来编译它,但这感觉更像是一种解决方法而不是解决方案。

提前感谢您的帮助。

编辑:我应该补充一点,在我的实际实现中,我有进一步限制Repr类型的子类,如果这有影响的话。

编辑 2:根据要求添加了更多代码。此问题也出现在BinarySearchTree 类型中,但不会出现在具体实现中,例如指定ReprScapegoatTree。还有一个基本的BinaryTree 的具体实现,但我尽量保持它的最小化,这样你就不必费力地处理太多不必要的代码。

【问题讨论】:

    标签: scala


    【解决方案1】:

    刚刚尝试使用类型参数而不是抽象类型进行重写,希望它适合您的需要。

    trait BinaryTree[T, Repr <: BinaryTree[T, Repr]] {
      def left: Repr
      def value: T
      def right: Repr
    
      def height: Int
      def add(elem: T): Repr =  
        if ( left.height <= right.height ) copy( left.add( elem ), right)
        else copy( left, right.add(elem))
    
      def copy( l: Repr, r: Repr ) : Repr
    }
    
    trait BinarySearchTree[T, U<:BinarySearchTree[T,U]] extends BinaryTree[T, U] { self:U =>
      def ordering: Ordering[T]
    
      override def add(elem: T) = 
        if ( ordering.equiv( elem, value ) ) self
        else if ( ordering.lt(elem, value) ) copy( left.add( elem ), right )
        else copy( left, right.add( elem ) )
    }
    
    class ScapegoatTree[T]( val value: T, val left: ScapegoatTree[T], val right: ScapegoatTree[T] )(implicit val ordering: Ordering[T]) extends BinarySearchTree[T, ScapegoatTree[T]] {
      override def height = 1
      override def copy( left: ScapegoatTree[T], right: ScapegoatTree[T] ) = new ScapegoatTree( value, left, right )
    }
    
    class BalancedBinaryTree[T]( val value: T, val left: BalancedBinaryTree[T], val right: BalancedBinaryTree[T] )(implicit val ordering: Ordering[T]) extends BinarySearchTree[T, BalancedBinaryTree[T]]{
      override def height = 1
      override def copy( left: BalancedBinaryTree[T], right: BalancedBinaryTree[T] ) = new BalancedBinaryTree( value, left, right )
    }
    

    根据this question,您遇到了“MyType”问题。

    【讨论】:

    • 嗯,这确实允许 BinaryTree 编译,但我有进一步限制 Repr 类型的子类,并且这种更改导致它们开始显示类似的错误。我尝试使用子类的 Repr 添加一个复制方法,但这只是重载了该方法。
    • 那么也许您可以发布您的子类代码,因为在不知道您实际在寻找什么的情况下很难找到答案。
    • 完成。当我尝试更改副本以采用 BinaryTree[T]#Repr 时,BinaryTree 可以编译,但 BinarySearchTree 开始给出错误,它需要 BinaryTree[T]#Repr 但它找到了 BinarySearchTree.this.Repr。
    猜你喜欢
    • 2012-07-06
    • 2010-10-24
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    相关资源
    最近更新 更多