2011-09-30 84 views
8

我試圖找出如何調用構造函數Scala的抽象類型:如何調用Scala抽象類型的構造函數?

class Journey(val length: Int) 
class PlaneJourney(length: Int) extends Journey(length) 
class BoatJourney(length: Int) extends Journey(length) 

class Port[J <: Journey] { 
    def startJourney: J = { 
    new J(23) // error: class type required but J found 
    } 
} 

這甚至是可行的?我熟悉Scala manifests,但我不清楚他們在這裏可以如何幫助。同樣我無法弄清楚如何做同樣的同伴對象的適用()構造函數:

object Journey { def apply() = new Journey(0) } 
object PlaneJourney { def apply() = new PlaneJourney(0) } 
object BoatJourney { def apply() = new BoatJourney(0) } 

class Port[J <: Journey] { 
    def startJourney: J = { 
    J() // error: not found: value J 
    } 
} 

任何想法感激地接受!

回答

7

沒有直接的方法來調用構造函數或只給出一個類型訪問伴隨對象。一種解決方案是使用構造給定類型的默認實例的類型類。

trait Default[A] { def default: A } 

class Journey(val length: Int) 
object Journey { 
    // Provide the implicit in the companion 
    implicit def default: Default[Journey] = new Default[Journey] { 
    def default = new Journey(0) 
    } 
} 

class Port[J <: Journey : Default] { 
    // use the Default[J] instance to create the instance 
    def startJourney: J = implicitly[Default[J]].default 
} 

您將需要一個隱含的Default定義添加到支持默認實例的創建類的所有同伴的對象。

+0

謝謝莫里茨 - 但是將代碼粘貼到REPL中會引發一些錯誤?另外如何將參數添加到默認的「構造函數」? –

+0

您必須爲此代碼輸入粘貼模式才能在REPL中工作(只需在粘貼前鍵入':paste')即可。 Philippe修復的代碼也存在錯誤。 – Moritz

+1

如果你想添加參數,你可以簡單地在'Default'特性中添加一個新的方法。 '默認[J]]'會給你一個帶有提供的類型參數的特性實例,你可以調用你喜歡的任何方法,例如, '隱式[默認[J]]。創建(23)'。請參閱示例[此問題](http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits)以瞭解有關隱含工作的詳細信息。 – Moritz

0

我的傾向是,這是不能做到的。我是遠從Scala的大師,但我的推理是這樣的:

  1. 你有一類口岸有一個類型參數T,其中T必須從旅程繼承(但T沒有要正好之旅,這很重要)。
  2. 在Port中,您定義了一個創建新T的方法。該類不知道T是什麼,因此T的構造函數看起來像什麼。
  3. 因爲你不知道T的構造函數需要什麼參數,所以你不知道傳遞給它的參數。

這個問題的解決方案中的另一個問題非常漂亮的處理,所以,我會爲你在那裏爲他們而不是在此重複:Abstract Types/Type Parameters in Scala

7

類別需要一個隱含的構造函數的參數,以獲得Manifest。然後你可以調用擦除來得到Class並且調用newInstance,如果有的話,它會反射地調用nullary構造函數。

class J[A](implicit m:Manifest[A]) { 
    def n = m.erasure.newInstance() 
} 

new J[Object].n 

作爲Scala的2.10,在清單中的erasure屬性已棄用。 def n = m.runtimeClass.newInstance()做同樣的事情,但沒有警告。

+0

這種方法不需要無參數的構造函數嗎? –

+0

@Chris它的確如此,這就是限制。除非你爲任何需要的工廠製造特質。 –

+0

謝謝金 - 很高興有newInstance()「構造函數」明確解釋 –