我正在阅读Debasish Ghosh的新书“功能和反应域建模”,我真的非常喜欢它。
第5章中让我困惑的一件事是下面的行:
Reporting.report(accts).foreach(println _)
可以使用Seq [Account]并将其转换为Seq [Show]。我知道implicits正在发挥作用,但编译器采取了哪些步骤来允许编译?这只是更一般的隐含规则的特定实例吗? 似乎就像编译器将Show trait混合到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 _)
}
}
答案 0 :(得分:3)
这是类型模式的非常简单的使用。所有的"魔法"发生在report
函数中。
首先注意类型参数:
def report[T: Show]
这意味着无论T
类型是什么,呼叫站点的范围内都必须有隐式Show[T]
。在Main
中,调用该函数T
为Account
,因此需要隐式Show[Account]
在该行的范围内。由于Main
混合在DomainShowProtocol
中,隐式val showAccount
在范围内,因此满足要求。
现在在report
的正文中,我们看到implicitly[Show[T]]
的使用。这只是返回对范围内所需的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 _)
答案 1 :(得分:1)
句法糖
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]]
,因为来自对象implicit
的{{1}}证据又来自特征{{1} }}
DomainShowProtocol
以上函数是
的语法糖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
。这就是这种转换的可能性。