2011-10-03 28 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我認爲你的意思是:你*不能*傳遞一個字符串到期望什麼都沒有的方法... –