Type Class Pattern

在理解scala type class之前应该先了解implicit在scala中的三种主要的用法:用于函数,用于参数,用于类。

type class pattern包含三个重要的组件:type class本身,type class的instances,和暴露给使用type class的接口函数(interface methods)。

1、 Type Class

type class用于表示我们需要实现一些功能的接口或API。在scala中,type class用一个包含至少一个类型变量(type parameter)的trai来构建。比如,我们可以使用下面的scala代码构建通用的json序列化方式。

// 定义一个非常简单的json AST
sealed trait Json
final case class JsObject(get: Map[String, Json]) extends Json
final case class JsString(get: String) extends Json
final case class JsNumber(get: Double) extends Json
case object JsNull extends Json

// 用于对将scala类实例转化位json
trait JsonWriter[A] {
def write(value: A): Json
}

这里,jsonWriter就是type class,A就是这个Type class的类型变量。

2、Type Class Instances

Type Class Instance 提供了我们关注的类型的具体实现。

在scala 中,我们通过定义实现type class的类,创建该type class的实现类的具体实例,并将该具体实例变量用implicit修饰来定义Instance。也就是说,定义一个Type Class 的Instance需要亮步:

​ 一、定义实现具体的Type class的类

​ 二 、创建 实现Type Class的类 的implicit实例变量

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...
}

上面的代码中,stringWriter和personWriter就是实现的Type Class的实例。

3、Type Class Interfaces

type class interface 是任何暴露给Type Class的使用者的功能(通常是通用的包含隐式变量(type class类型的实例)的函数)。有两种方式描述一个interface:Interface Objects 和
Interface Syntax.

**Interface Objects **

最简单的创建Interface的方式是在单例object中定义相应的函数:

object Json {
def toJson[A](value: A)(implicit w: JsonWriter[A]): Json =
w.write(value)
}

如果import了需要的type class instances(包含相关的隐式变量),我们就可以调用Object中的函数了。例如:

import JsonWriterInstances._
Json.toJson(Person("Dave", "dave@example.com"))
// res4: Json = JsObject(Map(name -> JsString(Dave), email -> JsString
(dave@example.com)))

**Interface Syntax **

我们可以在一个object中定义使用implicit修饰的类,并在该类中定义包含一个instance类型的隐式参数的函数来创建Interface。例如:

object JsonSyntax {
implicit class JsonWriterOps[A](value: A) {
def toJson(implicit w: JsonWriter[A]): Json =
w.write(value)
}
}

这样,我们可以在import我们需要的的类型的instances的时候紧接着import该instances对应的使用Interface Syntax

import JsonWriterInstances._
import JsonSyntax._
Person("Dave", "dave@example.com").toJson
// res6: Json = JsObject(Map(name -> JsString(Dave), email -> JsString (dave@example.com)))

上面例子中,先import了JsonWriterInstances._ (instance),然后import了JsonSyntax (Interface) ,这样,JsonSyntax中的函数toJson中的隐式变量就可以在JsonWriterInstances中找到。

编译器检测到Person(“Dave”, "dave@example.com")中的Person类没toJson方法,于是将Person(“Dave”, "dave@example.com")隐式转化为JsonWriterOps类型,当该转化的JsonWriterOps[Person]类型的实例调用toJson方法时,编译器将能在JsonWriterInstances中找到JsonWriter[Person]类型的的变量。

和下面代码等价:

new JsonWriterOps(Person("Dave","dave@example.com")).toJson(personWriter)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值