如何实现从类型类到接口语法的自动转换(Cats示例)

时间:2019-07-11 20:16:26

标签: scala implicit-conversion typeclass implicit scala-cats

我正在研究《带猫的scala》 书,我想知道库如何实现示例中描述的某些功能。具体来说,它是关于使用隐式转换从现有类型类定义自动生成隐式类的。

我具体指的是《斯卡拉与猫》一书中的练习1.4.6。为了完整起见,我复制了以下代码。

import cats.Show
import cats.instances.int._    
import cats.instances.string._
import cats.syntax.show._ 

final case class Cat(name: String, age: Int, color: String)

implicit val catShow = Show.show[Cat] { cat =>
  val name  = cat.name.show
  val age   = cat.age.show
  val color = cat.color.show
  s"$name is a $age year-old $color cat."
}

println(Cat("Garfield", 38, "ginger and black").show)

除了最后一行,我了解有关此示例的所有内容。 catShow隐式仅定义类型类。它没有定义一书中所说的“接口语法”。也就是说,它没有定义使最后一行起作用所需的隐式类。

该隐式类看起来像这样:

implicit class showCat(in: Cat) {
  def show: String = s"${in.name}, ${in.age}, ${in.color}"
}

很显然,我没有在任何地方定义此隐式类,这意味着它必须自动生成。我认为它必须使用某种隐式转换,将它从Show [Cat]实例转换为我上面创建的隐式类。

但是,我不确定如何编写此隐式类转换,并且想知道是否有人可以通过描述Cats库如何实现这一目标,或者通过为实现该目标的实现编写代码来帮助我同样好。

有关其他内容,请参阅免费的 Scala with Cats 书籍,网址为:https://books.underscore.io/scala-with-cats/scala-with-cats.html

1 个答案:

答案 0 :(得分:4)

这种隐式类可能看起来像泛型

handleLike

而不是具体

implicit class ShowOps[A: Show](in: A) {
  def show: String = implicitly[Show[A]].show(in)
}

因此隐式转换不必了解implicit class showCat(in: Cat) { def show: String = s"${in.name}, ${in.age}, ${in.color}" }

实际上,您使用Cat导入了类似的内容。

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/package.scala#L55

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/show.scala

https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/Show.scala#L23-L34