这里发生了什么 Scala 对 Seq 的隐式转换?
What Scala implicit conversion on a Seq is happening here?
我正在读 Debasish Ghosh 的新书,"Functional and Reactive Domain Modeling",我真的很喜欢。
第 5 章中让我感到困惑的一件事是下面的行:
Reporting.report(accts).foreach(println _)
可以使用 Seq[Account] 并将其转换为 Seq[Show]。我知道隐含函数在起作用,但编译器采取了哪些步骤来允许它编译?这只是更一般的隐含规则的一个具体实例吗? 似乎 编译器正在将 Show 特征混合到 Account 对象中。谢谢!
改编自第 164 页:
import scala.util.Try
trait Show[T] {
def shows(t: T): Try[String]
}
trait ShowProtocol {
implicit val showAccount: Show[Account]
implicit val showCustomer: Show[Customer]
}
trait DomainShowProtocol extends ShowProtocol {
override implicit val showAccount: Show[Account] = (t: Account) => Try("Account")
override implicit val showCustomer: Show[Customer] = (t: Customer) => Try("Customer")
}
case class Account()
case class Customer()
object Reporting {
def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)
}
object DomainShowProtocol extends DomainShowProtocol
object Main {
def main(args: Array[String]): Unit = {
import DomainShowProtocol._
val accts: Seq[Account] = Seq(
Account(),
Account(),
Account()
)
Reporting.report(accts).foreach(println _)
}
}
语法糖
def report[T: Show](seq: Seq[T])
是
的语法糖
def report(seq: Seq[T])(implicit evidence: Show[T])
你可以大致假设
[T: Show]
做
的工作
(implicit evidence: Show[T])
implicitly[Show[T]]
不过是隐式 Show[T]
的引用
特质DomainShowProtocol
有隐含证据Show[Account]
object DomainShowProtocol extends DomainShowProtocol
现在使用对象 DomainShowProtocol
隐式导入范围。
report
方法能够将 Seq[Account]
转换为 Seq[Try[String]]
,因为来自对象 DomainShowProtocol
的 implicit
证据又来自特征 DomainShowProtocol
def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)
以上函数是
的语法糖
def report(as: Seq[T])(implicit evidence: Show[T]): Seq[Try[String]] = as.map(evidence.shows _)
此处 T
是 Account
,隐含证据 Show[Account]
来自对象 DomainShowProtocol
。这就是这种转换的可能方式。
这是对类型类模式的一种非常直接的使用。所有 "magic" 都发生在 report
函数中。
首先注意类型参数:
def report[T: Show]
这意味着无论 T
是什么类型,在调用站点的范围内都必须有一个隐式的 Show[T]
。在 Main
中,函数被调用,其中 T
是 Account
,因此需要隐式 Show[Account]
在该行的范围内。由于 Main
混合在 DomainShowProtocol
中,隐式 val showAccount
在范围内,因此满足该要求。
现在在 report
的正文中,我们看到了 implicitly[Show[T]]
的用法。这只是 returns 对需要在范围内的 Show[T]
的引用,因此在这种情况下它等于 showAccount
.
最后,对隐式返回值调用 show
方法,将 Seq
的当前元素作为参数传入。这会将每个 Account
转换为 Try[String]
,从而将 Seq
作为一个整体。
如果我们删除所有隐含的魔法,方法及其调用如下所示:
//in Reporting
def report[T](as: Seq[T])(show: Show[T]): Seq[Try[String]] = {
as.map{t => show.shows(t)}
}
//in Main
Reporting.report(accts)(accountsShow).foreach(println _)
我正在读 Debasish Ghosh 的新书,"Functional and Reactive Domain Modeling",我真的很喜欢。
第 5 章中让我感到困惑的一件事是下面的行:
Reporting.report(accts).foreach(println _)
可以使用 Seq[Account] 并将其转换为 Seq[Show]。我知道隐含函数在起作用,但编译器采取了哪些步骤来允许它编译?这只是更一般的隐含规则的一个具体实例吗? 似乎 编译器正在将 Show 特征混合到 Account 对象中。谢谢!
改编自第 164 页:
import scala.util.Try
trait Show[T] {
def shows(t: T): Try[String]
}
trait ShowProtocol {
implicit val showAccount: Show[Account]
implicit val showCustomer: Show[Customer]
}
trait DomainShowProtocol extends ShowProtocol {
override implicit val showAccount: Show[Account] = (t: Account) => Try("Account")
override implicit val showCustomer: Show[Customer] = (t: Customer) => Try("Customer")
}
case class Account()
case class Customer()
object Reporting {
def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)
}
object DomainShowProtocol extends DomainShowProtocol
object Main {
def main(args: Array[String]): Unit = {
import DomainShowProtocol._
val accts: Seq[Account] = Seq(
Account(),
Account(),
Account()
)
Reporting.report(accts).foreach(println _)
}
}
语法糖
def report[T: Show](seq: Seq[T])
是
的语法糖def report(seq: Seq[T])(implicit evidence: Show[T])
你可以大致假设
[T: Show]
做
的工作(implicit evidence: Show[T])
implicitly[Show[T]]
不过是隐式 Show[T]
的引用特质DomainShowProtocol
有隐含证据Show[Account]
object DomainShowProtocol extends DomainShowProtocol
现在使用对象 DomainShowProtocol
隐式导入范围。
report
方法能够将 Seq[Account]
转换为 Seq[Try[String]]
,因为来自对象 DomainShowProtocol
的 implicit
证据又来自特征 DomainShowProtocol
def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)
以上函数是
的语法糖def report(as: Seq[T])(implicit evidence: Show[T]): Seq[Try[String]] = as.map(evidence.shows _)
此处 T
是 Account
,隐含证据 Show[Account]
来自对象 DomainShowProtocol
。这就是这种转换的可能方式。
这是对类型类模式的一种非常直接的使用。所有 "magic" 都发生在 report
函数中。
首先注意类型参数:
def report[T: Show]
这意味着无论 T
是什么类型,在调用站点的范围内都必须有一个隐式的 Show[T]
。在 Main
中,函数被调用,其中 T
是 Account
,因此需要隐式 Show[Account]
在该行的范围内。由于 Main
混合在 DomainShowProtocol
中,隐式 val showAccount
在范围内,因此满足该要求。
现在在 report
的正文中,我们看到了 implicitly[Show[T]]
的用法。这只是 returns 对需要在范围内的 Show[T]
的引用,因此在这种情况下它等于 showAccount
.
最后,对隐式返回值调用 show
方法,将 Seq
的当前元素作为参数传入。这会将每个 Account
转换为 Try[String]
,从而将 Seq
作为一个整体。
如果我们删除所有隐含的魔法,方法及其调用如下所示:
//in Reporting
def report[T](as: Seq[T])(show: Show[T]): Seq[Try[String]] = {
as.map{t => show.shows(t)}
}
//in Main
Reporting.report(accts)(accountsShow).foreach(println _)