2011-09-30 19 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

コンストラクタを呼び出す直接的な方法や、型だけが与えられたコンパニオンオブジェクトにアクセスする方法はありません。 1つの解決方法は、指定された型のデフォルトインスタンスを構築する型クラスを使用することです。

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

Moritzさんに感謝します - しかし、REPLにコードを貼り付けるといくつかのエラーが発生しますか?また、デフォルトの「コンストラクタ」にパラメータを追加するにはどうすればよいですか? –

+0

このコードがREPLで機能するには、貼り付けモードを入力する必要があります(貼り付ける前に ':paste'と入力するだけです)。 Philippeによって修正されたコードにもエラーがありました。 – Moritz

+1

パラメータを追加したい場合は、 'Default'特性に新しいメソッドを追加するだけです。 '暗黙的に[Default [J]]'は、指定された型パラメータを持つ型のインスタンスを与え、あなたが好きなメソッドを呼び出すことができます。 '暗黙的に[デフォルト[J]]。create(23)'。 implicitsの仕組みの詳細については、[この質問](http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits)を参照してください。 – Moritz

0

私の考えは、これはできないということです。私はこれまでScalaの第一人者からですが、私の推論はこれです:

  1. あなたはTが旅から継承しなければなりません(ただし、Tは正確ジャーニーである必要はありません型引数Tを持つクラスのポートを持って、このは重要)。
  2. ポート内では、新しいTを作成するメソッドを定義します。このクラスは、Tが何であるか、したがってTのコンストラクタの外観を知らない。
  3. Tのコンストラクタがどのような引数を取るか分からないので、どの引数を渡すべきかわからない。

この問題に対する解決策は、別の質問には非常にうまく処理されますので、私はむしろ、ここで繰り返すよりも、彼らのためにそこにあなたをポイントします:Abstract Types/Type Parameters in Scala

7

あなたのクラスはManifestを取得するための暗黙のコンストラクタのパラメータを必要とします。次に、消去を呼び出してClassを取得し、newInstanceを呼び出します。これは、nullaryコンストラクタがある場合はそれを反射的に呼び出します。スカラ2.10のよう

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

new J[Object].n 

、マニフェストにerasureプロパティは廃止されます。 def n = m.runtimeClass.newInstance()は同じことをしますが、警告は表示されません。

+0

この手法では、パラメータのないコンストラクタが必要ですか? –

+0

@Chrisそうです、それが限界です。どんな工場が必要なのかをあなたが特性をつけない限り。 –

+0

ありがとうKim - newInstance()の "コンストラクタ"を明確に説明していいです –

関連する問題