我看到了这段代码,不知道它将如何使用。我了解到implicit def
用于隐式转换,它附带了一个参数,这样它就可以将其参数转换为另一种类型。请帮助解释下面隐含的用法,任何例子都很好。提前谢谢!
implicit def eitherWrites[A: Writes, B: Writes] = Writes[Either[A, B]]({
case Left(a) => implicitly[Writes[A]].writes(a)
case Right(b) => implicitly[Writes[B]].writes(b)
})
eitherWrites
的类型参数中的语法A: Writes
被称为上下文绑定。
def foo[T: C]
是的句法糖
def foo[T](implicit evidence: C[T])
换句话说:eitherWrites
确实有两个(隐式(参数,而不是一个,因为它是的语法糖
implicit def eitherWrites[A, B](
implicit evidence`1: Writes[A],
evidence`2: Writes[B]
) = Writes[Either[A, B]]({
case Left(a) => implicitly[Writes[A]].writes(a)
case Right(b) => implicitly[Writes[B]].writes(b)
})
我可以向您展示一个不同的示例来了解implicit def
在您的案例中是如何使用的:
// a Haskell-like type class that provides textual representation
trait Show[T] {
def show(x: T): String
}
object Show {
def show[T: Show](x: T): String = implicitly[Show[T]].show(x)
implicit val showString: Show[String] = identity(_)
implicit val showInt: Show[Int] = _.toString
implicit def showTup[T: Show, U: Show]: Show[(T, U)] =
tup => s"(${Show.show[T](tup._1)}, ${Show.show[U](tup._2)})"
}
implicit def
被称为类型的类派生或隐式派生。基本上,它使您能够基于当前现有的隐式参数和隐式转换创建一个新的类型类,隐式转换描述了如何自动将它们组合在一起。
接下来的3行是等效的:
println(Show.show(123, "abc")) // (abc, 123)
println(Show.show((123, "abc"))) // (abc, 123)
println(Show.show(123 -> "abc")) // (abc, 123)
注意,这里的参数是一个由2个元素组成的元组,因为show
有一个参数。在这种情况下,编译器插入一个具有2个隐式参数的隐式转换。减温代码为:
println(Show.show(123, "abc")(showTup(showInt, showString)))
你也可以做:
println(Show.show((123, "abc"), (123, "abc"))) // ((123, abc), (123, abc))
要弄清楚编译器是如何翻译它的,这有点棘手,但一般规则仍然存在:隐式参数插入在一个单独的参数列表中的正常参数之后。减温代码为:
println(
Show.show((123, "abc"), (123, "abc"))(
showTup(showTup(showInt, showString), showTup(showInt, showString))
)
)
如果您自己无法解决,请使用-Xprint:typer
选项运行代码,在类型检查器添加了所有隐式转换后,scalac
编译器将向您显示代码的外观。
一开始这看起来很奇怪,但一旦你弄清楚了,它实际上是非常有限的,因为它只适用于2个元素的元组。例如,如果您想要一个由3个元素组成的元组,则必须编写另一个具有3个上下文边界的implicit def
,依此类推。