给出像
这样的多态特征 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 )
我得到编译器错误“type mismatch; found:Identity.type,required:Transform [String]”。为了使用它,我必须明确地使用它:
... Identity.asInstanceOf[Transform[String]]
我不确定这是最好还是“正确”的方式。谢谢你的任何建议。
答案 0 :(得分:5)
正如@Kim Stebel所指出的那样Transform[T]
在T
中是不变的(并且必须是因为T
出现在def apply(t : T) : T)
的共同和反对变体位置所以Transform[Nothing]
不是Transform[String]
的子类型,不能成为。{/ p>
如果您主要关注的是每次调用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
答案 1 :(得分:4)
由于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 = ""