2015-11-06 60 views
3
trait Thing { 
    type Out 
    def get: Out 
} 

case class Wrapper(t: Thing) extends Thing { 
    type Out = t.Out 
    override def get = t.get 
} 

def hey(t: Thing): t.Out = Wrapper(t).get 

這給了我一個類型錯誤,雖然它顯然是類型安全的。我想知道如何能夠向編譯器正確證明這是安全的,而無需執行演員。如何通過正確的包裝類線程類型?

任何想法?

+0

使用'def hey(t:Thing):Thing#Out = Wrapper(t).get'適用於我 – GClaramunt

+0

這個編譯,但它不比cast更好。>嘿(new Thing {type Out = Int; def get = 1}) res2:事情#出= 1 所以你沒有得到一個有用的靜態類型 –

回答

5

如果你真的,真的不希望把一個類型參數上Wrapper,您可以用較少的丟三落四apply推出自己的假案例類:

trait Thing { 
    type Out 
    def get: Out 
} 

abstract class Wrapper(t: Thing) extends Thing 

object Wrapper { 
    def apply(t: Thing): Wrapper { type Out = t.Out } = 
    new Wrapper(t) { 
     type Out = t.Out 
     def get: Out = t.get 
    } 
} 

def hey(t0: Thing): t0.Out = Wrapper(t0: Thing { type Out = t0.Out }).get 

(在現實生活中,你會還想要定義案例類給你的所有其他東西 - 有用的平等等)

問題是當定義一個case類時自動生成的Wrapper.apply只返回Wrapper,這意味着編譯器已經全部丟失有關其Out的靜態信息。如果您編寫自己的apply,則可以通過將返回類型設置爲指定Out的優化類型來保留該信息。

爲了證明它的工作原理:

scala> val myThing = new Thing { 
    | type Out = String 
    | def get = "foo" 
    | } 
myThing: Thing{type Out = String} = [email protected] 

scala> hey(myThing) 
res0: myThing.Out = foo 

scala> val foo: String = hey(myThing) 
foo: String = foo 

所以編譯器能夠跟蹤的事實OutString一路過關斬將。

+0

我看到...這很有道理 –

+0

一如既往,非常有幫助。 –

+0

非常好。包裝的目的只是爲了保存類型,對嗎? – GClaramunt