Scala Type Erasure对case类如何解决

ser*_*eda 2 scala implicit

我有一个特征和两个扩展它的案例类:

trait Authenticatable {
  val email: String
  val pass: String
  val id: Long
  val sessionid: String
}

case class Admin(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticatable

case class Client(
  id: Long,
  email: String,
  pass: String,
  sessionid: Option[String] = None) extends Authenticatable
Run Code Online (Sandbox Code Playgroud)

我有函数应该验证用户,用新的sessionid复制对象并返回它.

  def auth(email: String, password: String): Try[Admin] ={
    checkPass(models.Admin.findBy(sqls"email = $email"), password)
  }

  def auth(email: String, password: String, customer: Customer): Try[Customer] ={
    checkPass(models.Customer.findBy(sqls"email = $email"), password)
  }

  private def checkPass (model: Option[Authenticatable], password: String): Try[Authenticatable]={
    model match {
      case Some(m) => check(password, m.pass).map(_ => m)
      case _ => Failure(new Exception("Authentication failure!"))
    }
  }
Run Code Online (Sandbox Code Playgroud)

问题是:我无法在auth函数中复制对象,因为函数checkPass返回Authenticatable而不是Client或Admin类,而Authenticatable没有case类的复制方法.

解决这个问题的正确方法是什么?

Hug*_*ugh 5

如果使用类型参数,则可以避免丢弃checkPass始终返回与Authenticable给定类型相同的信息:

private def checkPass[A <: Authenticatable](model: Option[A], password: String): Try[A] =
  // exactly the same body here
Run Code Online (Sandbox Code Playgroud)

这意味着auth您可以拥有例如:

def auth(email: String, password: String): Try[Admin] =
  checkPass(models.Admin.findBy(sqls"email = $email"), password)
    .map(_.copy(sessionid = Some("whatever")))
Run Code Online (Sandbox Code Playgroud)