【问题标题】:Scala Implicit Parameters Projection Conflict , "Ambigious Implicit Values" ErrorScala隐式参数投影冲突,“模糊隐式值”错误
【发布时间】:2021-12-31 00:48:04
【问题描述】:

我一直在阅读 Bruno 的 TypeClasses 论文,他提到参数列表中的隐式被投影/传播到隐式范围。我按照这个代码的例子:

package theory

import cats.implicits.toShow

import java.io.PrintStream
import java.util.Date

object Equality extends App {
  import cats.Eq

//  assert(123 == "123")
  println(Eq.eqv(123, 123).show)

  implicit val out: PrintStream = System.out

  def log(m: String)(implicit o: PrintStream ): Unit =
    o.println(m)

  def logTime(m: String)(implicit  o: PrintStream): Unit =
    log(s"${new Date().getTime} : $m")

}

关键是这段代码将无法编译,其中:

ambiguous implicit values:
 both value out in object Equality of type java.io.PrintStream
 and value o of type java.io.PrintStream
 match expected type java.io.PrintStream
    log(s"${new Date().getTime} : $m")

所以,我假设编译器看到 2 个相同的隐式实例并抱怨。我可以通过显式添加作为参数传递的 PrintStream 作为日志的第二个参数来使编译器静音:

def logTime(m: String)(implicit  o: PrintStream): Unit =
    log(s"${new Date().getTime} : $m")(o)

这行得通,但我错过了什么吗?为什么 logTime() 的主体内部会出现混乱?我认为布鲁诺暗示来自调用者的隐含将被投射到方法的范围内。他的示例没有在 log() 调用中添加额外的参数。为什么scalac将这些视为2?我想我假设外部方法的隐含会“隐藏” val。不是这样。

如果有人能解释我为什么看到这个,将不胜感激。

【问题讨论】:

  • logTime 内部有两个有效的类型为PrintStream 的隐式值实例(顺便说一句,这是一种可怕的隐式类型),这使得它模棱两可,这是一个编译错误;期间。

标签: scala implicit


【解决方案1】:

回想一下,隐式参数的值是在调用站点确定的。这就是为什么...

Equality.log("log this")

...除非将适当类型的隐式值带入作用域,否则不会编译。

implicit val ps: PrintStream = ...
Equality.log("log this")

logTime() 定义代码是log() 方法的调用站点,并且由于它是在Equality 对象中定义的,因此它具有可用的implicit val out 值。但它也是从其调用站点传递的相同类型的 implicit o 值的接收者。从而产生歧义。编译器应该将implicit out 值还是implicit o 值发送到log() 方法?

现在,接收到的隐式值(来自调用站点)都分配给本地标识符 o 都插入到本地隐式命名空间中,这似乎有点奇怪.事实证明,Scala-3 已经修改了这种行为,即使没有新的 given/using 语法,您的代码也可以正确编译。 (我假设implicit out 值被传递给log() 方法,而不是接收到的o 值。)

【讨论】:

  • 基于您敏锐的眼光,我重构并删除了 Equality 对象中的隐含 val,然后 BAM!现在它按计划编译和工作!谢谢你的帮助!!!
猜你喜欢
  • 1970-01-01
  • 2021-05-02
  • 1970-01-01
  • 2015-05-14
  • 2016-07-25
  • 2012-02-21
  • 1970-01-01
  • 2013-05-06
  • 1970-01-01
相关资源
最近更新 更多