Scala 这里发生了什么样的序列隐式转换?
我正在读Debassh Ghosh的新书《功能性和反应性领域建模》,我真的很喜欢 第五章中有一件事让我感到困惑,那就是下面这句话:Scala 这里发生了什么样的序列隐式转换?,scala,implicit-conversion,Scala,Implicit Conversion,我正在读Debassh Ghosh的新书《功能性和反应性领域建模》,我真的很喜欢 第五章中有一件事让我感到困惑,那就是下面这句话: Reporting.report(accts).foreach(println _) 可以接受Seq[Account]并将其转换为Seq[Show]。我知道隐式在起作用,但是编译器采取了哪些步骤来编译它?这只是一个更一般的隐式规则的特定实例吗?似乎编译器正在将Show特性混合到Account对象中。谢谢 改编自第164页: import scala.util.Tr
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]]
只不过是暗示秀[T]的引用
traitDomainShowProtocol
有一个隐式证据Show[Account]
object DomainShowProtocol extends DomainShowProtocol
现在使用对象DomainShowProtocol
implicit导入范围
report
方法能够将Seq[Account]
转换为Seq[Try[String]]
,因为隐式的证据来自对象DomainShowProtocol
,而该证据又来自traitDomainShowProtocol
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
。这就是这种转换的可能方式。这是typeclass模式的一种非常直接的用法。所有的“魔法”都发生在报告
功能中
首先请注意类型参数:
def report[T: Show]
这意味着无论T
是什么类型,在调用站点的作用域中都必须有一个隐式的Show[T]
。在Main
中,当T
是Account
时调用该函数,因此要求隐式Show[Account]
在该行的范围内。由于Main
混合在DomainShowProtocol
中,隐式valshowAccount
在范围内,因此满足了要求
现在在报告
的主体中,我们看到了隐式[Show[T]]
的用法。这只是返回一个引用,引用的正是需要在范围内的Show[T]
,因此在本例中它等于showcount
最后,对隐式返回的值调用show
方法,将Seq
的当前元素作为参数传入。这会将每个帐户
转换为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 _)
谢谢你的编辑。他们真的帮助我获得了正在进行的语法分析,你在证据上做的笔记对我来说是全新的,所以谢谢你的“啊哈!”时刻!