Scala 这里发生了什么样的序列隐式转换?

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

我正在读Debassh Ghosh的新书《功能性和反应性领域建模》,我真的很喜欢

第五章中有一件事让我感到困惑,那就是下面这句话:

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]的引用

trait
DomainShowProtocol
有一个隐式证据
Show[Account]

object DomainShowProtocol extends DomainShowProtocol
现在使用对象
DomainShowProtocol
implicit导入范围

report
方法能够将
Seq[Account]
转换为
Seq[Try[String]]
,因为
隐式的
证据来自对象
DomainShowProtocol
,而该证据又来自trait
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
。这就是这种转换的可能方式。

这是typeclass模式的一种非常直接的用法。所有的“魔法”都发生在
报告
功能中

首先请注意类型参数:

def report[T: Show]
这意味着无论
T
是什么类型,在调用站点的作用域中都必须有一个隐式的
Show[T]
。在
Main
中,当
T
Account
时调用该函数,因此要求隐式
Show[Account]
在该行的范围内。由于
Main
混合在
DomainShowProtocol
中,隐式val
showAccount
在范围内,因此满足了要求

现在在
报告
的主体中,我们看到了
隐式[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 _)

谢谢你的编辑。他们真的帮助我获得了正在进行的语法分析,你在证据上做的笔记对我来说是全新的,所以谢谢你的“啊哈!”时刻!