Scala 类型 类 了解接口语法
Scala Type Classes Understanding Interface Syntax
我正在阅读有关猫的文章,我遇到了以下关于将对象序列化为 JSON!
的代码片段
它以这样的特征开始:
trait JsonWriter[A] {
def write(value: A): Json
}
在此之后,我们的域对象有一些实例:
final case class Person(name: String, email: String)
object JsonWriterInstances {
implicit val stringWriter: JsonWriter[String] =
new JsonWriter[String] {
def write(value: String): Json =
JsString(value)
}
implicit val personWriter: JsonWriter[Person] =
new JsonWriter[Person] {
def write(value: Person): Json =
JsObject(Map(
"name" -> JsString(value.name),
"email" -> JsString(value.email)
))
}
// etc...
}
到目前为止一切顺利!然后我可以这样使用它:
import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))
后来我遇到了一种称为接口语法的东西,它使用扩展方法通过如下接口方法扩展现有类型:
object JsonSyntax {
implicit class JsonWriterOps[A](value: A) {
def toJson(implicit w: JsonWriter[A]): Json =
w.write(value)
}
}
这样就简化了对 Person 序列化的调用:
import JsonWriterInstances._
import JsonSyntax._
Person("Dave", "dave@example.com").toJson
我不明白的是,Person 是如何装箱到 JsonWriterOps 中的,这样我就可以直接调用 toJson,就好像 toJson 是在 Person 案例 class 本身中定义的一样。我喜欢这种魔法,但我无法理解关于 JsonWriterOps 的最后一步。那么这个接口语法背后的想法是什么,它是如何工作的呢?有帮助吗?
这实际上是一个标准的 Scala 功能,因为 JsonWriterOps
被标记为 implicit
并且在范围内,编译器可以在需要时在编译时应用它。
因此 scalac 将进行以下转换:
Person("Dave", "dave@example.com").toJson
new JsonWriterOps(Person("Dave", "dave@example.com")).toJson
new JsonWriterOps[Person](Person("Dave", "dave@example.com")).toJson
旁注:
像这样将 类 隐式为值 类 效率更高:
implicit class JsonWriterOps[A](value: A) extends AnyVal
这使得编译器也优化了新对象的构造,如果可能的话,将整个隐式转换+方法调用编译为一个简单的函数调用。
我正在阅读有关猫的文章,我遇到了以下关于将对象序列化为 JSON!
的代码片段它以这样的特征开始:
trait JsonWriter[A] {
def write(value: A): Json
}
在此之后,我们的域对象有一些实例:
final case class Person(name: String, email: String)
object JsonWriterInstances {
implicit val stringWriter: JsonWriter[String] =
new JsonWriter[String] {
def write(value: String): Json =
JsString(value)
}
implicit val personWriter: JsonWriter[Person] =
new JsonWriter[Person] {
def write(value: Person): Json =
JsObject(Map(
"name" -> JsString(value.name),
"email" -> JsString(value.email)
))
}
// etc...
}
到目前为止一切顺利!然后我可以这样使用它:
import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))
后来我遇到了一种称为接口语法的东西,它使用扩展方法通过如下接口方法扩展现有类型:
object JsonSyntax {
implicit class JsonWriterOps[A](value: A) {
def toJson(implicit w: JsonWriter[A]): Json =
w.write(value)
}
}
这样就简化了对 Person 序列化的调用:
import JsonWriterInstances._
import JsonSyntax._
Person("Dave", "dave@example.com").toJson
我不明白的是,Person 是如何装箱到 JsonWriterOps 中的,这样我就可以直接调用 toJson,就好像 toJson 是在 Person 案例 class 本身中定义的一样。我喜欢这种魔法,但我无法理解关于 JsonWriterOps 的最后一步。那么这个接口语法背后的想法是什么,它是如何工作的呢?有帮助吗?
这实际上是一个标准的 Scala 功能,因为 JsonWriterOps
被标记为 implicit
并且在范围内,编译器可以在需要时在编译时应用它。
因此 scalac 将进行以下转换:
Person("Dave", "dave@example.com").toJson
new JsonWriterOps(Person("Dave", "dave@example.com")).toJson
new JsonWriterOps[Person](Person("Dave", "dave@example.com")).toJson
旁注:
像这样将 类 隐式为值 类 效率更高:
implicit class JsonWriterOps[A](value: A) extends AnyVal
这使得编译器也优化了新对象的构造,如果可能的话,将整个隐式转换+方法调用编译为一个简单的函数调用。