给定多态性特征,如
trait Transform[T] { def apply( t: T ) : T }
人们可能想实现各种专门的实例,例如
case class Add[Double] extends Transform[Double] { def apply( t: Double ) ... }
case class Append[String] extends Transform[String] { def apply( t: String ) ... }
等等。现在经常需要的变换也是恒等变换。与其为每种类型 T 专门化标识,不如为所有类型 T 只使用一个单例实例。我的问题是:在 Scala 中实现这一目标的最佳方法是什么?
这是我到目前为止发现的:查看 List[T] 如何实现 List.empty[T] 和 Nil,我尝试使用 Nothing 作为类型 T。这似乎是有道理的,因为 Nothing 是所有其他类型的子类型:
object Identity extends Transform[Nothing] {
def apply( t: Nothing ) = t
}
这似乎有效。但是,无论我在哪里想按原样使用此实例,就像这里一样:
val array = Array[Transform[String]]( Transform.Identity )
我收到编译器错误“类型不匹配;发现:Identity.type,必需:Transform[String]”。为了使用它,我必须显式地转换它:
... Identity.asInstanceOf[Transform[String]]
我不确定这是最好的,甚至是“正确”的方法。感谢您的任何建议。
正如@Kim Stebel指出的那样,你的
Transform[T]
在T
中是不变的(并且必须是因为T
同时出现在def apply(t : T) : T)
中的同变体和逆变体位置,所以Transform[Nothing]
不是的子类型) Transform[String]
并且无法做到。
如果您主要关心的是 Kim 的
def Id[A]
每次调用时的实例创建,那么您最好的模型是 Predef 中 conforms
的定义,
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
即。使用多态方法,返回一个转换为适当类型的单例值。这是删除就是胜利的场合之一。
适用于您的情况,我们会,
object SingletonId extends Transform[Any] { def apply(t : Any) = t }
def Id[A] = SingletonId.asInstanceOf[Transform[A]]
示例 REPL 会话,
scala> Id("foo")
res0: java.lang.String = foo
scala> Id(23)
res1: Int = 23
由于
T
中的类型参数Transform[T]
是不变的,Transform[Nothing]
不是Transform[String]
的子类型,因此编译器会抱怨它。但在这里使用 Nothing
无论如何都没有意义,因为永远不可能有 Nothing
的实例。那么如何将一个传递给 apply
方法呢?你需要再次施放。我能看到的唯一选项是:
scala> def Id[A] = new Transform[A] { override def apply(t:A) = t }
Id: [A]=> java.lang.Object with Transform[A]
scala> Id(4)
res0: Int = 4
scala> Id("")
res1: java.lang.String = ""