首页 > 解决方案 > 为什么这个隐含的决议失败了?

问题描述

我有一个隐式转换 - 下面 - 感觉它肯定应该工作,但绝对不是。任何人都可以解释一下吗?我知道implicitly在使用类型改进时有时会失败 - 这是这里的问题吗?

trait GetItem[A[_], T, R] {
  type Out
  def ret(a: A[T], ref: R): Out
}
object GetItem {
  implicit def ifRefIsInt[A[_], T]: GetItem[A, T, Int] { type Out = A[T] } = new GetItem[A, T, Int] {
    type Out = A[T]
    def ret(a: A[T], ref: Int): Out = a
  }
}
import GetItem._
//this works fine:
val t: GetItem[List, Double, Int] { type Out = List[Double] } = ifRefIsInt[List, Double]
// so does this:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }](t)
// this does not:
implicitly[GetItem[List, Double, Int] { type Out = List[Double] }] 
// Could not find implicit parameter for value e: Example.Main.GetItem[List, Double, Int]{type Out = List[Double]}

非常感谢任何帮助,我已经盯着这个看了一段时间,但收效甚微。

标签: scalatypeclassimplicit

解决方案


不知道为什么它不能那样工作,但是解决这类问题的一个好技术是使用Aux模式将类型成员提升为类型参数,这可以提高分辨率。

trait GetItem[A[_], T, R] {
  type Out
  def ret(a: A[T], ref: R): Out
}

object GetItem {
  type Aux[A[_], T, R, O] = GetItem[A, T, R] { type Out = O }

  implicit def ifRefIsInt[A[_], T]: Aux[A, T, Int, A[T]] = new GetItem[A, T, Int] {
    type Out = A[T]
    def ret(a: A[T], ref: Int): Out = a
  }
}

您可以像这样测试:

implicitly[GetItem.Aux[List, Double, Int, List[Double]]]
// res: GetItem.Aux[List, Double, Int, List[Double]] = ...

implicitly[GetItem[List, Double, Int]] 
// res: GetItem[List, Double, Int] = ...

推荐阅读