[英]Scala generics: specializing a method
In Haskell I can define a generic type for a tree as: 在Haskell中,我可以为树定义泛型类型:
type Tree t = Leaf t | Node (Tree t) (Tree t)
If I want to define a function for a specific parameterization of Tree, I can simply do: 如果我想为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
We can define a similar tree type in Scala with: 我们可以在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]
But how can I define a method for Tree that only applies to certain types? 但是,如何为Tree定义仅适用于某些类型的方法? Do I need to use inheritance or there's a way to say: 我需要使用继承还是有办法说:
abstract class Tree[T]() {
// Method only for Tree[String]:
def foo[String] = ...
}
In Haskell types don't have instance methods like Scala does. 在Haskell类型中没有像Scala那样的实例方法。
foo
in your example should be defined (preferably) in Tree
's companion object. 你的例子中的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 a sealed
class or trait is more appropriate here. PS:IMO sealed
类或特性在这里更合适。 ( Scala's sealed abstract vs abstract class ) ( Scala的密封抽象与抽象类 )
PS II: I am just typing Gregor Raýman's comment as an answer. PS II:我只是输入GregorRaýman的评论作为答案。
This may not be the answer you are looking for, as I haven't done much Haskell, but it's a possibility: You can define a trait
that can only be mixed into specific instances of a tree: 这可能不是你要找的答案,因为我没有做过太多的Haskell,但它是一个可能性:你可以定义一个trait
,只能混合成树的具体情况:
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
}
You would use this like this: 你可以这样使用:
val sNode = new Node(Leaf("a"), Leaf("b")) with StringFooFunctionality
sNode.foo
// Yay
The downside is that it explicitly needs to be mixed in on object creation. 缺点是明确需要在对象创建中混合使用。
Other possibility is to create a new trait called StringTree
: 其他可能性是创建一个名为StringTree
的新特征:
trait StringTree extends Tree[String] {
def foo = ...
}
But you would have to define the other String
datatypes: 但您必须定义其他String
数据类型:
case class StringLeaf(t: String) extends StringTree
case class StringNode(left: StringTree, right: StringTree) extends StringTree
And when you encounter a Tree[T]
you can pattern match on it to see if it's StringTree
. 当你遇到Tree[T]
你可以在它上进行模式匹配,看看它是否是StringTree
。
The obvious way (and equivalent to Haskell) is to define a method which takes Tree[String]
as an argument, as in muhuk's answer. 显而易见的方法(相当于Haskell)是定义一个将Tree[String]
作为参数的方法,就像muhuk的答案一样。 If you want it to look like a method on Tree[String]
, you can use implicit class: 如果你希望它看起来像Tree[String]
上的方法,你可以使用隐式类:
implicit class Foo(val tree: Tree[String]) {
def foo = ...
}
val tree: Tree[String] = ...
tree.foo // Foo needs to be in scope here
I recommend avoiding Akos Krivachy's answer in most circumstances. 我建议在大多数情况下避免使用Akos Krivachy的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.