Scala案例类:如何为成员设置计算值

时间:2018-07-21 07:42:33

标签: scala

我想生成一个随机数以存储在case类的“ id”成员中,并在存储在数据库中时用作主键。如果传递的id值非零,则应使用该值,而不要生成新的值。

case class User(name: String, id: Long = 0L)

我尝试过

object User {
  def apply(name: String, id: Long): User = 
    User(name, (id == 0L) ? <some random number> : id)
}

但是会出现一些错误,例如:

ambiguous reference to overloaded definition
...
method apply is defined twice

我不想在案例类中引入其他成员。

4 个答案:

答案 0 :(得分:4)

作为错误消息的统计信息,您将覆盖您的apply方法。您应该在new定义中使用apply

object User {
  def apply(name: String, id: Long): User = 
   new User(name, if(id == 0L)  <some random number> else id)
}

答案 1 :(得分:1)

此处不支持?:三元运算符。错误apply method defined twice被定义为case class。但是即使在case class的定义中,它也已在scala 2.12.6中成功编译。我改成这个,然后编译:

  class User(name: String, id: Long = 0L)
  object User {
  def apply(name: String, id: Long): User =
   new User(name,if(id == 0L) scala.util.Random.nextLong else id)
  }

在Scala REPL中:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class User(name: String, id: Long = 0L)
object User {
  def apply(name: String, id: Long): User =
   new User(name,if(id == 0L) scala.util.Random.nextLong else id)}

// Exiting paste mode, now interpreting.

defined class User
defined object User

scala>

答案 2 :(得分:1)

其他人指出,scala使用if ... else而不是Java的? .. : ..(在解决了“应用两次定义”问题之后,您将收到此错误)。

直接的问题是,案例类具有为它们生成的默认apply方法,带有案例类的参数,因此您要定义的是重复的。

您可以通过以下方法解决此问题:从构造函数中删除默认值,然后从apply中删除第二个参数:

   case class User(name: String, id: Long)
   object User { def apply(name: String) = User(name, Random.nextLong) }

这将进行编译,而且效果更好,因为您不再需要将0视为前哨值。当您执行User(name, 1)时,将调用默认的apply,并获得具有给定ID的实例,当您执行User(name)时,它将调用自定义apply,并获得一个随机ID ,

我想,您知道在这种简单情况下,您可以做

case class User(name: String, id: Long = Random.nextLong)

,对吧?当一个(或多个)参数的默认值取决于其他参数的值时,这种方法(带有重载)更有用,这样您就不能只在参数列表中写入默认值,例如:< / p>

case class Parent(child: Person, lastName: String)
object Parent { 
   def apply(child: Person) = Parent(child, child.lastName)
}

答案 3 :(得分:0)

我通常的做法是这样的

case class User(name: String, private val _id: Long = 0L) {
  lazy val id: Long = if(_id == 0) Random.nextLong() else _id
}

编辑:请注意,这种方法在案例类上有违反平等合同的缺点:您通过_id = 0传递的2个User实例将具有不同的ID,但相等,因为case类的equals方法仅查看构造函数的参数