为什么我不能解压此 Scala 模式匹配中的值?

Why can't I unpack the value in this scala pattern match?

我正在尝试在 scala 中使用 slick(带有 unicorn)查找用户。这是我的代码:

class UserRepository extends BaseIdRepository[UserId, User, Users](TableQuery[Users]) with IdentityService[User] {

  /**
   * Retrieve the User associated with the given LoginInfo, if any. This method
   * is required by Silhouette.
   * @param loginInfo
   */
  override def retrieve(loginInfo: LoginInfo): Future[Option[User]] = {
    Future.successful {
      val loginInfoRepository = new LoginInfoRepository
      loginInfoRepository.find(loginInfo) match {
        case Some(retrievedLoginInfo) =>
          val userLoginInfoJunctionRepository = new UserLoginInfoJunctionRepository
          // problem here...
          userLoginInfoJunctionRepository.forB(retrievedLoginInfo.id).firstOption
        case None => None
      }
    }
  }
}

class LoginInfoRepository extends BaseIdRepository[DbLoginInfoId, DbLoginInfo, LoginInfos](TableQuery[LoginInfos]) {
  def find(loginInfo: LoginInfo) = query.filter(
    l =>
      l.providerID == loginInfo.providerID &&
      l.providerKey == loginInfo.providerKey
  ).firstOption
}

在上面标记的行中,intellij 打印 "type mismatch. Expected DbLoginInfoId, actual Option[DbLoginInfoId]".

我是不是在一个选项中有一个选项,所以 retrievedLoginInfo 实际上是一个 Option[retrievedLoginInfo]?我怎样才能正确解压,以便我可以访问 retrievedLoginInfo?

的 ID

我觉得不错。我认为问题中缺少一些信息?

一旦我围绕这段代码填充了足够的上下文,它就会编译。此代码中属于您的部分未更改:

import scala.concurrent.Future

package object foo {

  trait LoginInfo {
    def providerID: Any
    def providerKey: Any
  }
  abstract class BaseIdRepository[A, B, C](x: Any)
  trait IdentityService[A] {
    def retrieve(loginInfo: LoginInfo): Future[Option[User]]
  }
  trait User {
    def id: UserId
  }
  trait UserId
  trait Users
  def TableQuery[A] = ???
  class UserLoginInfoJunctionRepository {
    def forB(x: UserId): QueryResult[User] = ???
  }
  trait DbLoginInfoId
  trait DbLoginInfo
  trait LoginInfos
  trait QueryResult[A] {
    def firstOption: Option[A] = ???
  }
  class Query {
    def filter(f: LoginInfo => Boolean): QueryResult[User] = ???
  }
  val query = new Query()

  // ----

  class UserRepository extends BaseIdRepository[UserId, User, Users](TableQuery[Users]) with IdentityService[User] {

    /**
     * Retrieve the User associated with the given LoginInfo, if any. This method
     * is required by Silhouette.
     * @param loginInfo
     */
    override def retrieve(loginInfo: LoginInfo): Future[Option[User]] = {
      Future.successful {
        val loginInfoRepository = new LoginInfoRepository
        loginInfoRepository.find(loginInfo) match {
          case Some(retrievedLoginInfo) =>
            val userLoginInfoJunctionRepository = new UserLoginInfoJunctionRepository
            // problem here...
            userLoginInfoJunctionRepository.forB(retrievedLoginInfo.id).firstOption
          case None => None
        }
      }
    }
  }

  class LoginInfoRepository extends BaseIdRepository[DbLoginInfoId, DbLoginInfo, LoginInfos](TableQuery[LoginInfos]) {
    def find(loginInfo: LoginInfo) = query.filter(
      l =>
        l.providerID == loginInfo.providerID &&
          l.providerKey == loginInfo.providerKey
    ).firstOption
  }
}

如果你能trim将问题简化为一个最小的例子,那就容易多了。

看起来 LoginInfo 上的 idOption[DbLoginInfoId] 类型,但 forB 需要 DbLoginInfoId.

您需要映射 retrievedLoginInfo.id 以提取实际值。您可以通过更好的理解来重构整个事物,例如:

for {
  retrievedLoginInfo <- loginInfoRepository.find(loginInfo)
  id <- retrievedLoginInfo.id
  userLoginInfoJunctionRepository = new UserLoginInfoJunctionRepository
  res <- userLoginInfoJunctionRepository.forB(id).firstOption
} yield res