如何在 Scala 中创建 object/singleton 泛型?
How to create object/singleton of generic type in Scala?
在下面显示的代码中,如何将 EmptyTree
转换为对象(单例)?
trait Tree[T] {
def contains(num: T): Boolean
def inc( num: T ): Tree[T]
}
class EmptyTree[T <% Ordered[T] ] extends Tree[T] {
def contains(num:T):Boolean = false
def inc(num:T):Tree[T] = {
new DataTree(num, new EmptyTree, new EmptyTree)
}
override def toString = "."
}
class DataTree[T <% Ordered[T] ](val x:T, val left:Tree[T], val right:Tree[T]) extends Tree[T] {
def contains(num:T):Boolean = {
if( num < x ) left.contains(x)
else if ( num > x ) right.contains(x)
else true
}
def inc(num:T):Tree[T] = {
if(num < x ) new DataTree(x, left.inc(num), right)
else if ( num > x ) new DataTree(x, left, right.inc(num))
else this
}
override def toString = "{" + left + x + right + "}"
}
val t = new DataTree(20, new EmptyTree[Int], new EmptyTree[Int])
//> t : greeting.Test.DataTree[Int] = {.20.}
val p = t.inc(10) //> p : greeting.Test.Tree[Int] = {{.10.}20.}
val a = p.inc(30) //> a : greeting.Test.Tree[Int] = {{.10.}20{.30.}}
val s = a.inc(5) //> s : greeting.Test.Tree[Int] = {{{.5.}10.}20{.30.}}
val m = s.inc(11) //> m : greeting.Test.Tree[Int] = {{{.5.}10{.11.}}20{.30.}}
您必须修复通用参数,因为这是您唯一可以提供的时间:
scala> trait A[T]
defined trait A
scala> object B extends A[Int]
defined object B
显然你想为所有类型的 T
重用 EmptyTree
,所以不要为每个类型定义 A[SOMETYPE]
,只需使用底部类型 Nothing
:
scala> object B extends A[Nothing]
defined object B
此对象可用于任何树。
这正是 Option[T]
在 Scala 中的实现方式。 None
的定义如下:
case object None extends Option[Nothing]
如果保留泛型,还可以选择添加空工厂 - 就像对 Map 和 Vector 所做的那样。当然,通过这样的实现,它不会是每次创建的唯一实例对象,但是当使用 inc
方法时,它不会产生新对象,它只会引用自己。
object DataTree {
def empty[T <% Ordered[T]] = new Tree[T] {
def contains(num: T):Boolean = false
def inc(num: T): Tree[T] = {
new DataTree(num, this, this)
}
override def toString = "."
}
}
因此您可以将其实例化如下:
val t = new DataTree(20, DataTree.empty[Int], DataTree.empty[Int])
让我详细解释一下 Alexey 的回答。这是带有一些代码风格改进的完整实现:
首先定义你的特征并了解它的协方差:
trait Tree[+T] {
def contains[U >: T : Ordering](num: U): Boolean
def inc[U >: T : Ordering](num: U): Tree[U]
}
接下来定义所有树的子类型对象
case object EmptyTree extends Tree[Nothing] {
def contains[U >: Nothing : Ordering](num: U): Boolean = false
def inc[U >: Nothing : Ordering](num: U): Tree[U] =
DataTree(num, EmptyTree, EmptyTree)
override def toString = "."
}
现在更改您的一般案例实施:
case class DataTree[T: Ordering](x: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
import Ordering.Implicits._
def contains[U >: T : Ordering](num: U): Boolean =
if (num < x) left.contains(x)
else if (num > x) right.contains(x)
else true
def inc[U >: T : Ordering](num: U): Tree[U] =
if (num < x) DataTree(x, left.inc(num), right)
else if (num > x) DataTree(x, left, right.inc(num))
else this
override def toString = "{" + left + x + right + "}"
}
你可能会有点沮丧,因为我用 Ordering
替换了你的 Ordered
,但你应该知道 view bounds are deprecated
在下面显示的代码中,如何将 EmptyTree
转换为对象(单例)?
trait Tree[T] {
def contains(num: T): Boolean
def inc( num: T ): Tree[T]
}
class EmptyTree[T <% Ordered[T] ] extends Tree[T] {
def contains(num:T):Boolean = false
def inc(num:T):Tree[T] = {
new DataTree(num, new EmptyTree, new EmptyTree)
}
override def toString = "."
}
class DataTree[T <% Ordered[T] ](val x:T, val left:Tree[T], val right:Tree[T]) extends Tree[T] {
def contains(num:T):Boolean = {
if( num < x ) left.contains(x)
else if ( num > x ) right.contains(x)
else true
}
def inc(num:T):Tree[T] = {
if(num < x ) new DataTree(x, left.inc(num), right)
else if ( num > x ) new DataTree(x, left, right.inc(num))
else this
}
override def toString = "{" + left + x + right + "}"
}
val t = new DataTree(20, new EmptyTree[Int], new EmptyTree[Int])
//> t : greeting.Test.DataTree[Int] = {.20.}
val p = t.inc(10) //> p : greeting.Test.Tree[Int] = {{.10.}20.}
val a = p.inc(30) //> a : greeting.Test.Tree[Int] = {{.10.}20{.30.}}
val s = a.inc(5) //> s : greeting.Test.Tree[Int] = {{{.5.}10.}20{.30.}}
val m = s.inc(11) //> m : greeting.Test.Tree[Int] = {{{.5.}10{.11.}}20{.30.}}
您必须修复通用参数,因为这是您唯一可以提供的时间:
scala> trait A[T]
defined trait A
scala> object B extends A[Int]
defined object B
显然你想为所有类型的 T
重用 EmptyTree
,所以不要为每个类型定义 A[SOMETYPE]
,只需使用底部类型 Nothing
:
scala> object B extends A[Nothing]
defined object B
此对象可用于任何树。
这正是 Option[T]
在 Scala 中的实现方式。 None
的定义如下:
case object None extends Option[Nothing]
如果保留泛型,还可以选择添加空工厂 - 就像对 Map 和 Vector 所做的那样。当然,通过这样的实现,它不会是每次创建的唯一实例对象,但是当使用 inc
方法时,它不会产生新对象,它只会引用自己。
object DataTree {
def empty[T <% Ordered[T]] = new Tree[T] {
def contains(num: T):Boolean = false
def inc(num: T): Tree[T] = {
new DataTree(num, this, this)
}
override def toString = "."
}
}
因此您可以将其实例化如下:
val t = new DataTree(20, DataTree.empty[Int], DataTree.empty[Int])
让我详细解释一下 Alexey 的回答。这是带有一些代码风格改进的完整实现:
首先定义你的特征并了解它的协方差:
trait Tree[+T] {
def contains[U >: T : Ordering](num: U): Boolean
def inc[U >: T : Ordering](num: U): Tree[U]
}
接下来定义所有树的子类型对象
case object EmptyTree extends Tree[Nothing] {
def contains[U >: Nothing : Ordering](num: U): Boolean = false
def inc[U >: Nothing : Ordering](num: U): Tree[U] =
DataTree(num, EmptyTree, EmptyTree)
override def toString = "."
}
现在更改您的一般案例实施:
case class DataTree[T: Ordering](x: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
import Ordering.Implicits._
def contains[U >: T : Ordering](num: U): Boolean =
if (num < x) left.contains(x)
else if (num > x) right.contains(x)
else true
def inc[U >: T : Ordering](num: U): Tree[U] =
if (num < x) DataTree(x, left.inc(num), right)
else if (num > x) DataTree(x, left, right.inc(num))
else this
override def toString = "{" + left + x + right + "}"
}
你可能会有点沮丧,因为我用 Ordering
替换了你的 Ordered
,但你应该知道 view bounds are deprecated