Scala 方法隐式转换不起作用

scala method implicit convertion not working

我有一个 Play 2.3 项目,自定义 headers 来自 AJAX,需要传递给每个服务调用(进一步传递给网络服务)。我想过让它成为一个隐式参数,就像在这个简单的例子中一样:

case class CriteriaHeaders(license: String)
case class Criteria(criteriaHeaders: CriteriaHeaders, id: Int)

class ProjectController(service: Service)  {
  implicit def criteriaToCiteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
  def findName(criteria: Criteria) = {
    // implicit val criteriaHeaders: CriteriaHeaders = criteria.criteriaHeaders
    service
      .findName(criteria.id)
      .fold(
        error => error,
        name => name
      )
  }
}

class Service {
  def findName(id: Int)
              (implicit criteriaHeaders: CriteriaHeaders): Either[String, String] = ??? // TODO
}

(当然在实际项目中还有一个ActionBuilder,一个Json解析器等等)

用法:

val controller = new ProjectController(new Service())
val name = controller.findName(Criteria(CriteriaHeaders("abc"), 123))

编译不通过,报错:

Error:(21, 17) could not find implicit value for parameter licenseHeaders: A$A172.this.CriteriaHeaders.findName(criteria.id)

但是,如果我取消对隐式 val 的注释,它就会起作用。为什么它不适用于隐式方法?

编辑: 如果有人觉得这有用,我从@till-rohrmann 那里采纳了第二个建议,并将隐式放在 CriteriaHeaders 的同伴 object 中,因此它在每个使用它的控制器中都可用。

object CriteriaHeaders {
  implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria) = criteria.criteriaHeaders
}

问题在于,不会调用采用显式参数的隐式转换来获取 Service.findName 方法的隐式参数。您的问题有两种解决方案。

  1. 调用带有显式第二个参数列表和 Criteria 参数的 findName 方法。然后编译器知道它必须将 criteria 值转换为 CriteriaHeaders.
class ProjectController(service: Service)  {
  implicit def criteriaToCriteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
  def findName(criteria: Criteria) = {
    service
      .findName(criteria.id)(criteria)
      .fold(
        error => error,
        name => name
      )
  }
}
  1. 使ProjectController.criteriaToCriteriaHeadersProjectController.findName的参数criteria隐式化。然后将使用隐式转换。
class ProjectController(service: Service)  {
  implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
  def findName(implicit criteria: Criteria) = {
    service
      .findName(criteria.id)
      .fold(
         error => error,
         name => name
      )
  }
}