Scala:对多态类型的单例实例使用Nothing

时间:2011-10-03 05:54:32

标签: scala singleton polymorphism nothing

给出像

这样的多态特征
 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]]

我不确定这是最好还是“正确”的方式。谢谢你的任何建议。

2 个答案:

答案 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 = ""