Scala泛型:专门研究方法

时间:2015-06-11 15:26:05

标签: scala generics

在Haskell中,我可以将树的泛型类型定义为:

type Tree t = Leaf t | Node (Tree t) (Tree t)

如果我想为Tree的特定参数化定义一个函数,我可以这样做:

-- Signature of a function that takes a tree of bool
foo :: Tree Bool -> Int

-- Takes a tree of numbers
bar :: (Num n) => Tree n -> Bool

我们可以在Scala中定义类似的树类型:

abstract class Tree[T]()
case class Leaf[T](t: T) extends Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]

但是如何为Tree定义仅适用于某些类型的方法?我需要使用继承还是可以说:

abstract class Tree[T]() {
  // Method only for Tree[String]:
  def foo[String] = ...
}

3 个答案:

答案 0 :(得分:2)

在Haskell类型中没有像Scala那样的实例方法。

您的示例中的

foo应该在Tree的伴随对象中定义(最好)。

sealed abstract class Tree[T]()
case class Leaf[T](t: T) extends Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]

object Tree {
  // Method only for Tree[String]:
  def foo(tree: Tree[String]) = ...
}

PS:IMO sealed类或特征在这里更合适。 (Scala's sealed abstract vs abstract class

PS II:我只是输入GregorRaýman的评论作为答案。

答案 1 :(得分:1)

这可能不是您正在寻找的答案,因为我没有做太多Haskell,但它有可能:您可以定义一个只能混合到树的特定实例中的trait: / p>

trait StringFooFunctionality {
   this: Tree[String] => // Selftype, can only be mixed in to classes that are Tree[String]
   def foo = "Yay" // String is the datatype of Tree here
}

您可以这样使用:

val sNode = new Node(Leaf("a"), Leaf("b")) with StringFooFunctionality
sNode.foo
// Yay

缺点是明确需要在对象创建中加入。

其他可能性是创建一个名为StringTree的新特征:

trait StringTree extends Tree[String] {
   def foo = ...
}

但您必须定义其他String数据类型:

case class StringLeaf(t: String) extends StringTree
case class StringNode(left: StringTree, right: StringTree) extends StringTree

当您遇到Tree[T]时,您可以在其上进行模式匹配,看看它是否为StringTree

答案 2 :(得分:0)

显而易见的方法(相当于Haskell)是定义一个以Tree[String]为参数的方法,就像muhuk的回答一样。如果您希望它看起来像Tree[String]上的方法,则可以使用隐式类:

implicit class Foo(val tree: Tree[String]) {
  def foo = ...
}

val tree: Tree[String] = ...

tree.foo // Foo needs to be in scope here

我建议在大多数情况下避免使用Akos Krivachy的答案。