1

ユーザーが名前パラメーターを提供しない場合に備えて、適切なデフォルトを提供しようとしています。Eclipse IDE の Scala ワークシートで次の操作を行うと、コンパイラ エラーが発生します。

case class Type(id: Int, name: String, description: String = "")
case class Definition(id: Int, types: List[Type], separator: String = ";", name: String = types.mkString(separator))

エラーは、List の mkString メソッド呼び出し内の識別子「separator」に示されている「not found: value separator」です。これはケース クラスであり、以前のパラメータは既に定義されているため、name のデフォルト値を定義する際に「セパレータ」を使用できないのはなぜですか。そして、「名前」のデフォルト値を定義する際に「タイプ」を使用することさえできないことがわかりました。

私はこれを回避しようとしましたが、name を var に変換しないと方法がわかりません。これは私がやりたいことではありません。これに関するガイダンスまたは理解をいただければ幸いです。

更新:わかりました、これを回避するために私が見つけた方法は、コンパニオンオブジェクトを使用してコンストラクターに転送することでした:

  case class Type(id: Int, name: String, description: String = "")
  object Definition {
    def create(id: Int, types: List[Type], separator: String = ";", name: String = "") =
      Definition(id, types, separator, if (name != "") name else types.map(_.name).mkString(separator))
  }
  case class Definition(id: Int, types: List[Type], separator: String = ";", name: String) {
    require(!separator.isEmpty, "separator must not be empty")
    require(!name.isEmpty, "name must not be empty")
  }

これは確かに、私が最初にやろうとしたことと比較して、Java のようなボイラープレートです。これを行う他の/より良い方法はありますか?

4

3 に答える 3

3

Definition のコンストラクターでは、パラメーターは他のパラメーターを参照できません。

scala> case class Foo(x: Int, y: Int = x + 1)
<console>:7: error: not found: value x
       case class Foo(x: Int, y: Int = x + 1)
                                       ^

コンストラクターの引数をカリー化することもできませんが、機能しているように見えます。

scala> case class Foo(x: Int)(y: Int = x + 1)
defined class Foo

scala> val test = Foo(3)()
test: Foo = Foo(3)

scala> test.y
<console>:11: error: value y is not a member of Foo
              test.y
                   ^

Definition のコンパニオン オブジェクトに追加の apply メソッドを定義することで、ご希望の効果を得ることができました。

case class Type(id: Int, name: String, description: String = "")
case class Definition(id: Int, types: List[Type], separator: String, name: String)
object Definition {
  def apply(id: Int, types: List[Type], separator: String): Definition = Definition(id, types, separator, types.mkString(separator))  
  def apply(id: Int, types: List[Type]): Definition = Definition(id, types, ";")
}

これらはコンストラクターではなく通常のメソッドであるため、メソッドの本体で必要に応じて引数を参照および操作できます。例えば:

// Entering paste mode (ctrl-D to finish)

val type1 = Type(1, "foo")
val type2 = Type(2, "bar", "not baz")
val myDef = Definition(1, List(type1, type2))

// Exiting paste mode, now interpreting.

type1: Type = Type(1,foo,)
type2: Type = Type(2,bar,not baz)
myDef: Definition = Definition(1,List(Type(1,foo,), Type(2,bar,not baz)),;,Type(1,foo,);Type(2,bar,not baz))
于 2013-10-02T22:23:29.433 に答える
2

name新しい引数リストを入れるだけで、これを回避できます。後続の引数リストのパラメーターは、前のリストのパラメーターの値を参照でき、それらから型を推測することもできます。

case class Definition(id: Int, types: List[Type], separator: String = ";")(name_ : String = types.mkString(separator)) {
  def name = name_
}
于 2013-10-02T21:49:19.557 に答える
0

おそらくあなたが望むのは次のようなものです:

case class Type(id: Int, name: String, description: String = "")
case class Definition(id: Int, types: List[Type], separator:String, name: String)
object Definition{
  def apply(id: Int, types: List[Type], separator: String = ";") : Definition = 
    Definition(id,types,separator,types.mkString(separator))
}

これは、Shadowlands のソリューションに似ています。

于 2013-10-02T22:25:05.173 に答える