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
方法的隐式参数。您的问题有两种解决方案。
- 调用带有显式第二个参数列表和
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
)
}
}
- 使
ProjectController.criteriaToCriteriaHeaders
和ProjectController.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
)
}
}
我有一个 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
方法的隐式参数。您的问题有两种解决方案。
- 调用带有显式第二个参数列表和
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
)
}
}
- 使
ProjectController.criteriaToCriteriaHeaders
和ProjectController.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
)
}
}