scala - 类型类解析中的隐式类别
问题描述
我猜测,
大多数人都知道Show示例要引入类型类。
我发现了这篇博文https://scalac.io/typeclasses-in-scala/,当我偶然发现一些我不太理解的东西并希望有人可以帮助澄清它时,我很容易就解决了。
我理解博客文章中关于隐式类别的所有内容:
从具有语法和对象接口的类型类完整定义
trait Show[A] {
def show(a: A): String
}
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
//needed only if we want to support notation: show(...)
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
//type class instances
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
我们得到以下评论:
我们可能会遇到需要重新定义一些默认类型类实例。通过上面的实现,如果所有默认实例都被导入作用域,我们就无法实现。编译器将在范围内具有模棱两可的隐式并报告错误。
我们可能决定将 show 函数和 ShowOps 隐式类移动到另一个对象(比如说 ops),以允许此类型类的用户重新定义默认实例行为(使用类别 1 隐式,更多关于隐式类别)。经过这样的修改,Show 对象如下所示:
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
object ops {
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
}
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
用法没有改变,但现在这个类型类的用户只能导入:
import show.Show
import show.Show.ops._
默认隐式实例不作为第 1 类隐式引入(尽管它们可作为第 2 类隐式使用),因此可以在使用此类类型类的地方定义我们自己的隐式实例。
我没有得到最后的评论?
解决方案
Show[Int]
和在伴随对象Show[String]
中定义的隐式实例,因此无论何时使用类型的值,类型类实例都将可用。但是,它们可以被用户覆盖。这使它们成为第 2 类隐含物——它们来自隐含作用域。Show
Show
另一方面,通过直接导入引入范围的隐式是第 1 类隐式。它们来自本地范围,不能被覆盖。因此,直接导入隐式与在现场定义它们相同 - 两者都被视为第 1 类。如果在本地范围内存在多个相同类型的第 1 类隐式值,编译器会报错。
文章所说的是,将您的隐式实现放在伴随对象中,但将“机器”放在ops
. 这样,您的类型类的用户可以只导入允许他们执行 eg 的机制42.show
,而无需将类型类实例作为类别 1 值引入。
然后我们的用户可以执行以下操作:
import show.Show
import show.Show.ops._
// available from Show as category 2 implicit:
println(42.show) // "int 42"
也:
import show.Show
import show.Show.ops._
// overriding category 2 implicit with our own category 1 implicit:
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
println(42.show) // prints "my own 42"
但是,如果我们没有ops
对象并且我们只是将所有内容放入Show
对象中,那么无论何时我们的用户会做import Show._
(并且他们需要,为了能够做42.show
)他们都会收到我们所有的隐含作为类别 1 值和将无法覆盖它们:
import show.Show
// Assuming everything is in `Show` (no `ops`)...
import show.Show._
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
// this line doesn't compile because implicits were brought
// into scope as category 1 values (via import Show._)
println(42.show)
推荐阅读
- javascript - JS 控制台变量输出问题
- android-studio - OnClickerListener 问题,可以在模拟器中打开应用
- amazon-web-services - 一次提交的 AWS CodePipeline 双重执行
- c# - 减少重复 - 从实例方法创建委托
- python-3.x - 如何使用python从HTML页面的javascript代码中抓取数据
- azure - Azure 备份无法删除备份项
- python - 使用 Python 去除 CSV 文件中除一列之外的引号
- python - 未能将对象编组到 TFJob;规范无效:未能将对象编组到 TFJob
- r - 运行博客中的确切代码时出现错误
- python - 如何将旅行推销员问题 (TSP) 与 Haversine 距离列表一起使用?