2011-10-03 79 views
2

给出一个多态特质像斯卡拉:没有使用多态类型的单实例

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,需要:变换[字符串]”。为了使用它,我必须明确地施放它:

... Identity.asInstanceOf[Transform[String]] 

我不确定这是最好的,甚至是“正确的”方法。感谢您的任何建议。

回答

5

由于@Kim Stebel指出你的Transform[T]T不变(而一定是因为发生在双方合作和禁忌变异位置在def apply(t : T) : T)所以Transform[Nothing]T不是的Transform[String]亚型,不能做成。

如果您主要关注的是金正日的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] 

ie。使用多态方法,将单例值转换为适当的类型。这是擦除是胜利的场合之一。

适用于您的情况,我们会的,

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 
+0

所以铸造一个单独的对象是正确的方法。现在你的代码使用Identity [Any]而不是Identity [Nothing]。要么似乎工作,就演员而言,似乎这没关系。那么是否有任何错误?在lib中,Nil的类型为List [Nothing]。 –

+0

'任何'在这里都是正确的选择。你期望有转换类型的值(即有'SingletonId.apply'将被应用到的东西),你不能说他们的类型是什么。另一方面,'Nil'中的'Nothing'正在捕捉一个事实,即没有任何值对应于空列表的头部。 –

4

由于Transform[T]中的类型参数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 = "" 
+0

右键,使用工厂函数,而不是一个单一实例会工作,这就是我有它在我的代码现在。但是我看到List使用一个单例类型为Nothing(无),所以我认为这可能更好。传递值不是问题:我会传递String或Double或任何我需要的值。然而,你对类型差异问题是正确的,也许这是关键。 –

+1

传递值是问题。您可以将String传递给期望Nothing的方法,因为Nothing不是String的子类型,而不是VICE VERSA。 –

+0

@Kim Stebel我认为你的意思是:你*不能*传递一个字符串到期望什么都没有的方法... –