Scala 类型类模式中隐式定义的运行时成本
Runtime cost of implicit definitions in Scala's typeclass pattern
我正在查看 this 文章,关于如何在 Scala 中使用隐式模拟类型类。
如果我没记错的话,每次使用递归实例声明的类型类方法时,都会在运行时构造一个新实例 (Printer a => Printer (Option a)
)。这是代码,每次使用 print
时都会在运行时创建一个新的 Printer
实例。无论如何,是否可以重用为特定类型创建的实例(在本例中为Option[Int]
)?
trait Printer[T] {
def print(t: T): String
}
object Printer {
implicit val intPrinter: Printer[Int] = new Printer[Int] {
def print(i: Int) = s"$i: Int"
}
implicit def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] =
new Printer[Option[V]] {
println("New Option Printer")
def print(ov: Option[V]) = ov match {
case None => "None"
case Some(v) => s"Option[${pv.print(v)}]"
}
}
}
object Main {
def print[T](t: T)(implicit p: Printer[T]) = p.print(t)
def main(args: Array[String]): Unit = {
val res3 = print(Option(1))
val res4 = print(Option(2))
println(s"res3: ${res3}")
println(s"res4: ${res4}")
}
}
// New Option Printer
// New Option Printer
// res3: Option[1: Int]
// res4: Option[2: Int]
你是对的。在您的示例中,每次调用都会创建一个新实例。但是,有几种方法可以处理它。根据我的经验,您最终会得出以下经验法则:
首先,不要过早优化,确保额外的实例确实是一个问题。
如果您确定它与性能相关,您只需编写大量 val
s.
即可应对
object Printer {
implicit val intPrinter: Printer[Int] = new Printer[Int] {
def print(i: Int) = s"$i: Int"
}
// make sure this is not visible, as you do not want to have productive code create new instances on demand
private[this] def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] =
new Printer[Option[V]] {
println("New Option Printer")
def print(ov: Option[V]) = ov match {
case None => "None"
case Some(v) => s"Option[${pv.print(v)}]"
}
}
implicit val intOptPrinter: Printer[Option[Int]] = optionPrinter[Int]
}
我认为,使用 shapeless 可以实现更高级的解决方案。但是,恕我直言,为此需要对类型 类 和类型级编程有深入的了解。
也可以考虑使用Typelevel的Machinist
项目。
它提供宏来消除与 implicit class
扩展方法相关的运行时成本。
我正在查看 this 文章,关于如何在 Scala 中使用隐式模拟类型类。
如果我没记错的话,每次使用递归实例声明的类型类方法时,都会在运行时构造一个新实例 (Printer a => Printer (Option a)
)。这是代码,每次使用 print
时都会在运行时创建一个新的 Printer
实例。无论如何,是否可以重用为特定类型创建的实例(在本例中为Option[Int]
)?
trait Printer[T] {
def print(t: T): String
}
object Printer {
implicit val intPrinter: Printer[Int] = new Printer[Int] {
def print(i: Int) = s"$i: Int"
}
implicit def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] =
new Printer[Option[V]] {
println("New Option Printer")
def print(ov: Option[V]) = ov match {
case None => "None"
case Some(v) => s"Option[${pv.print(v)}]"
}
}
}
object Main {
def print[T](t: T)(implicit p: Printer[T]) = p.print(t)
def main(args: Array[String]): Unit = {
val res3 = print(Option(1))
val res4 = print(Option(2))
println(s"res3: ${res3}")
println(s"res4: ${res4}")
}
}
// New Option Printer
// New Option Printer
// res3: Option[1: Int]
// res4: Option[2: Int]
你是对的。在您的示例中,每次调用都会创建一个新实例。但是,有几种方法可以处理它。根据我的经验,您最终会得出以下经验法则:
首先,不要过早优化,确保额外的实例确实是一个问题。
如果您确定它与性能相关,您只需编写大量 val
s.
object Printer {
implicit val intPrinter: Printer[Int] = new Printer[Int] {
def print(i: Int) = s"$i: Int"
}
// make sure this is not visible, as you do not want to have productive code create new instances on demand
private[this] def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] =
new Printer[Option[V]] {
println("New Option Printer")
def print(ov: Option[V]) = ov match {
case None => "None"
case Some(v) => s"Option[${pv.print(v)}]"
}
}
implicit val intOptPrinter: Printer[Option[Int]] = optionPrinter[Int]
}
我认为,使用 shapeless 可以实现更高级的解决方案。但是,恕我直言,为此需要对类型 类 和类型级编程有深入的了解。
也可以考虑使用Typelevel的Machinist
项目。
它提供宏来消除与 implicit class
扩展方法相关的运行时成本。