2017-11-04 3 views
0

私はオブジェクトのコレクションを持っています。それぞれのオブジェクトは異なるクラスのコンパニオンです。これらのクラスはすべて、スーパークラスで定義された共通メソッドを共有しています。foreach()でコレクションをループするときに呼び出すことができます。私は、これらの兄弟クラスのコンストラクタが同じ名前のパラメータとデフォルトのパラメータ値をお互いに持つことを望みます。最後に、繰り返しコードを最小限に抑えたい。名前付きパラメータとデフォルト値を使用して兄弟インスタンスを構築できる要素を持つスカラコレクション?

これまでは、ケースクラスでこれを実行しようとしていました。それが機能すれば、各タイプのコンパニオンオブジェクトの重複コードをすべて削除するからです。問題は、これらのコンパニオンオブジェクトをすべてSetに入れた場合、それらを再び取り出しても、デフォルトのパラメータとパラメータ名が失われることです。ここで

は私が記述しています何のいくつかのサンプルコードです:Setは一つだけの要素を持っている場合は特に

trait MyType { 
    val param: String 
    def label = param // all instances of all subclasses have this method 
} 

case class caseOne(override val param: String = "default") extends MyType 
case class caseTwo(override val param: String = "default") extends MyType 

object Main extends App { 
    // I can construct instances using the companion objects' `apply()` method: 
    val works1 = caseOne(param = "I have been explicitly set").label 
    // I can construct instances that have the default parameter value 
    val works2 = caseOne().label 

    // But what I want to do is something like this: 
    val set = Set(caseOne, caseTwo) 
    for { 
    companion <- set 
    } { 
    val fail1 = companion()      // Fails to compile--not enough arguments 
    val fail2 = companion(param = "not default") // Fails also as param has lost its name 
    val succeeds = companion("nameless param") // this works but not what I want 
    println(fail1.label + fail2.label)   // this line is my goal 
    } 
} 

、それは多要素Setの推論された型は、パラメータを欠い示唆、コンパイル名 - - それらは同じですが、デフォルト値です。また、私がSetに正しいタイプのパラメータを与えれば、これはうまくいく可能性があることを示唆しています。しかし、そのタイプは何ですか?それはMyTypeではないので、それはSetのオブジェクトではなく、コンパニオンクラスの型です。

私はコンパニオンオブジェクトを明示的に定義することができますが、これは避けたい繰り返しのコードです。

各ループでMyTypeサブクラスのインスタンスを構築し、希望のパラメータ名とデフォルト値を持つコンストラクタを使用して、ループをループするにはどうすればよいですか?すべて繰り返しコードを最小限に抑えながら?

更新:当初のコード例は、paramに異なるデフォルト値を有するものとしてcaseOnecaseTwoを示しました。それは間違っていた。彼らは今同じです。

答えて

0

自動生成されたコンパニオンオブジェクトを実際にはほとんど制御できないので、あなたが望むものを正確に得ることはできません。特にこれが機能するためには、共通の特性を広げる必要があります。これは、セットに複数のコンパニオンオブジェクトがある場合にコンパイルが失敗する理由です。彼らはすべて同じシグネチャを持つメソッドを持っていますが、コンパイラが利用する共通の特性を拡張しません。

あなたは、ネストされたケースクラスを使用し、しかし非常によく似た何かを得ることができます。

trait MyType { 
    val param: String 
    def label = param // all instances of all subclasses have this method 
} 

abstract class MyTypeHelper(default: String) { 

    case class Case(param: String) extends MyType 

    def apply(param: String) : Case = Case(param) 
    def apply(): Case = apply(default) 
} 

object One extends MyTypeHelper("default one") 
object Two extends MyTypeHelper("default two") 

object Example { 

    val works1 = One(param = "I have been explicitly set").label 
    val works2 = One().label 

    val set = Set(One, Two) 
    for { 
    companion <- set 
    } { 
    val a = companion()      
    val b = companion(param = "not default") 
    val c = companion("nameless param") 
    println(a.label + b.label)   
    } 
} 

が代わりにcaseOne型を有する、あなたはOne.Caseを持っているが、それはまだMyTypeを実装していますので、どこでもすべての問題を持つべきではありませんそうでない場合はその特性を使用するコード内にあります。

+0

このように見えます、ありがとうございます!注:元のサンプルコードでエラーが発生しました.2つのケースクラスは同じデフォルト値を持つ必要があります。私はあなたの 'MyTypeHelper'をデフォルト値を定義する単一の' apply() 'メソッドで使用することができ、' MyTypeHelper'コンストラクタから 'default'パラメータを削除しました。また、ケースクラスをケースクラスから通常クラスに変更しました。これは1文字を節約します。あなたは私をくつろいだ。もう一度、ありがとう! –

関連する問題