问题描述
我是Typeclass模式的新手,并且在scala中是隐式的,下面是我测试该模式的代码片段,但我不知道为什么compareB方法无法为参数找到隐式值wrapper ,即使这样,我也声明了一个IntWrapper [Int]类型的隐式字段。
有人知道在typeclass中如何解析隐式吗?以及为什么下面的代码无法编译?
谢谢
trait IntWrapper[T]{
def test: Boolean
}
trait ProductComparator[T] extends Serializable{
def compare(p1 : T,p2: T): Boolean
}
object ProductComparator{
def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
implicit def CompareB[T <: Product,Repr <: HList,KRepr <: HList](implicit gen: LabelledGeneric.Aux[T,Repr],keys: Keys.Aux[Repr,KRepr],wrapper: IntWrapper[Int]) : ProductComparator[T] =
new ProductComparator[T] {
override def compare(p1: T,p2: T): Boolean = {
p1.productArity == p2.productArity
}
}
}
case class Emp(a: Int,b: Int)
object Demo extends App{
val comparator = implicitly[ProductComparator[Emp]]
}
解决方法
通常将类型为TC[A]
的隐式对象放到TC
的伴随对象或A
的伴随对象中。
所以转移
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
从ProductComparator
的伴随对象到IntWrapper
的伴随对象
object IntWrapper {
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
}
然后代码应编译。
或者,您也可以按照 @TomerShetah 的建议导入w
。
Where does Scala look for implicits?
定义时
implicit val foo: Foo = ???
def bar(implicit foo1: Foo) = ???
(在您的示例中,foo
是w
,bar
是CompareB
,Foo
是IntWrapper[Int]
)
您通常不应该假设foo1
是foo
。 foo
在当前范围内定义,foo1
将在bar
呼叫站点范围内解决。如果它在范围内或其他隐式范围内,则可以为foo
。
When doing implicit resolution with type parameters,why does val placement matter?
Setting abstract type based on typeclass
Reverse HList and convert to class?
,问题是范围。在该行中:
val comparator = implicitly[ProductComparator[Emp]]
方法:
def apply[A](implicit cmp: ProductComparator[A]): ProductComparator[A] = cmp
将被调用,其中A
是Emp
。可以创建该隐式的是CompareB
。 CompareB
需要更多的隐式。前两个来自进口。因此,它们在范围内。变量w
是在object ProductComparator
上定义的,因此它不在您定义val comparator
的范围内。
要将其添加到范围中,您有几个选择:
-
将其导入:
import ProductComparator.w
-
将
implicit def w: IntWrapper[Int]
移动到与trait IntWrapper[T]
相同的范围,这使得:
import shapeless.ops.record.Keys
import shapeless.{HList,LabelledGeneric}
trait IntWrapper[T]{
def test: Boolean
}
implicit def w: IntWrapper[Int] =
new IntWrapper[Int] {
override def test: Boolean = true
}
trait ProductComparator[T] extends Serializable{
def compare(p1 : T,p2: T): Boolean
}
object ProductComparator{
def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp
implicit def CompareB[T <: Product,Repr <: HList,KRepr <: HList](implicit gen: LabelledGeneric.Aux[T,Repr],keys: Keys.Aux[Repr,KRepr],wrapper: IntWrapper[Int]) : ProductComparator[T] =
new ProductComparator[T] {
override def compare(p1: T,p2: T): Boolean = {
p1.productArity == p2.productArity
}
}
}
case class Emp(a: Int,b: Int)
object Demo extends App{
val comparator = implicitly[ProductComparator[Emp]]
}
要了解有关Scala在哪里寻找隐式信息的更多信息,请阅读Daniels brilliant post。