1

如果用户不提供 name 参数,我试图提供一个合理的默认值。在 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 方法调用内的标识符“分隔符”上指示。既然这是一个案例类,而且前面的参数已经定义好了,为什么我不能使用“分隔符”来定义名称的默认值。事实证明,我什至不能使用“类型”来定义“名称”的默认值。

我试图解决这个问题,但是如果不将 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

在定义的构造函数中,参数不能引用其他参数:

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)
                                       ^

你也不能 curry 构造函数参数,尽管它看起来可以工作:

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
                   ^

通过在定义的伴随对象中定义额外的应用方法,我能够达到您想要的效果:

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 回答