【问题标题】:Extending existing data structure in Scala在 Scala 中扩展现有数据结构
【发布时间】:2010-05-09 09:19:09
【问题描述】:

我在 Scala 中定义了一棵普通树。

sealed abstract class Tree
object Tree {
  case class Node (...) extends Tree
  case class Leaf (...) extends Tree
}

现在我想为树中的所有节点和叶子添加一个成员变量。 是否可以使用extend关键字或者我必须通过添加[T]来修改树类?

更新:
看来我的问题被误解了。 示例应该清除它:

我需要这个 Tree 结构(实际上更复杂)在一个上下文中有两个 Double。 在另一种情况下,我需要它有一个字符串。然而在另一种情况下,我需要没有任何(额外)成员的纯树。我希望前两个变体成为第三个​​变体。 伪代码:

DTree extends Tree with Touple2[Double, Double]
object DTree {
  case class Node (...) extends Tree.Node with Touple2[Double, Double]
  case class Leaf (...) extends Tree.Leaf with Touple2[Double, Double]
}

STree extends Tree with String
object DTree {
  case class Node (...) extends Tree.Node with String
  case class Leaf (...) extends Tree.Leaf with String
}

...

def f (t : Tree) { ... }

我希望 f 能够处理所有的树。

【问题讨论】:

    标签: data-structures scala scala-2.8


    【解决方案1】:

    如果我理解正确,您希望您的某些树节点具有具有该类型字段的类型。我认为abstract type 是您正在寻找的。它们就像泛型,但更适合子类化。像这样。

    sealed abstract class Tree
    
    trait TypedTree {
      type T
      val value:T
    }
    

    然后,当我修改您的示例时,结果是:

    trait DTree extends TypedTree {
      type T = Touple2[Double, Double]
    }
    object DTree {
      case class Node (...) extends Tree.Node with DTree 
      case class Leaf (...) extends Tree.Leaf with DTree 
    }
    
    trait STree extends TypedTree {
      type T = String
    }
    object DTree {
      case class Node (...) extends Tree.Node with STree
      case class Leaf (...) extends Tree.Leaf with STree
    }
    

    这增加了一个间接级别。但我感觉你是一步概念化的东西,其中两个是必要的。

    【讨论】:

      【解决方案2】:

      您不必修改树类,因为您始终可以在树和节点/叶子之间创建一个中间子类:

      abstract class ExtraMember[T](member:T) extends Tree

      但是,如果您希望将额外成员作为参数传递,则无法通过将特征混合到 Node 和 Leaf 来实现。

      【讨论】:

        【解决方案3】:

        抽象类可能有构造函数(trait 可能没有),所以你可以把公共元素放在abstract class Tree

        abstract
        class Tree(te1: String, te2: Int)
        
        case
        class Node(...)
        extends Tree(te1Arg, te2Arg)
        

        等等。请注意,您必须在子类定义的extends 子句中提供基类构造函数参数。

        【讨论】:

        • 你修改了 Tree 类。我想避免这种情况,因为它在很多地方都使用过,而我只需要在一个地方使用更丰富的树。
        • @Łukasz Lew:然后在继承结构中引入一个新层,用于捕获这种区别并将共享元素放入该级别的(抽象)类之一中。
        【解决方案4】:

        如果您添加的成员对所有 Tree 对象(和子类)都有效,那么合乎逻辑的地方是将它们放在 Tree 对象本身中。

        这里有两种可用的技术。正如其他人所提到的,您可以在抽象类上制作这些构造函数参数:

        sealed abstract class Tree(prop1: String, prop2: Int)
        
        case class Node(prop1: String, prop2: Int) extends Tree(prop1, prop2)
        

        您还可以使它们成为常规的 vals/vars 并专门研究子类。这可以说是一个更好的解决方案,因为它可以更轻松地计算这些属性,而不是通过构造函数简单地以菊花链形式连接它们:

        sealed abstract class Tree {
          def prop1 : String
          def prop2 : Int
        }
        
        case class Node(a:String, b:Int) extends Tree {
          lazy val prop1 = "[" + a + "]"
          lazy val prop2 = b + 42
        }
        

        在此处使用惰性 val 可以更轻松地推断对象的初始化顺序,如果从不使用该属性,它还可以避免任何计算开销。这也很好地展示了 Scala 中的方法是如何通过属性实现的,即所谓的统一访问原则。

        如果你采用这种方法,那么也可以通过 trait 引入属性:

        sealed abstract class Tree
        
        trait TreeExtras {
          def prop1 : String
          def prop2 : Int
        }
        
        case class Node(a:String, b:Int) extends Tree with TreeExtras {
          lazy val prop1 = "[" + a + "]"
          lazy val prop2 = b + 42
        }
        

        您还应该酌情使用自我类型等。

        【讨论】:

          猜你喜欢
          • 2012-01-09
          • 1970-01-01
          • 2010-12-13
          • 2012-03-30
          • 2014-04-08
          • 2011-10-29
          • 1970-01-01
          • 2020-05-17
          • 2011-12-23
          相关资源
          最近更新 更多