【问题标题】:Could not find implicit value while using Context Bound使用上下文绑定时找不到隐式值
【发布时间】:2023-03-06 08:07:02
【问题描述】:

我正在使用以下用 Scala 2.11.8 编写的代码:

  sealed trait Acceptable[T]

  object Acceptable {
    implicit object Int extends Acceptable[Int]

    implicit object String extends Acceptable[String]
  }

  case class Enc[T](f: T => Any)

  implicit def test[I, T](implicit f: I => T, a: Acceptable[T]): Enc[I] =
    Enc[I](f)

  val e = implicitly[Enc[Int]]

编译成功。

如您所见,a: Acceptable[T] 参数应该很容易转换为context bound

implicit def test[I, T: Acceptable](implicit f: I => T): Enc[I] =
    Enc[I](f)

但是在那之后,编译开始失败并出现错误:

找不到参数 e 的隐含值:app.Enc[Int]

为什么会这样?

更新:

我尝试了-Xlog-implicits 编译器选项,编译日志给了我:

[info] /path/to/ScalaTest/src/main/scala/app/Main.scala:60: test is not a valid implicit value for app.Enc[Int] because:
[info] hasMatchingSymbol reported error: ambiguous implicit values:
[info]  both object Int in object Acceptable of type app.Acceptable.Int.type
[info]  and object String in object Acceptable of type app.Acceptable.String.type
[info]  match expected type app.Acceptable[T]
[info]   val e = implicitly[Enc[Int]]
[info]                     ^
[info] /path/to/ScalaTest/src/main/scala/app/Main.scala:60: app.test is not a valid implicit value for app.Enc[Int] because:
[info] hasMatchingSymbol reported error: ambiguous implicit values:
[info]  both object Int in object Acceptable of type app.Acceptable.Int.type
[info]  and object String in object Acceptable of type app.Acceptable.String.type
[info]  match expected type app.Acceptable[T]
[info]   val e = implicitly[Enc[Int]]
[info]                     ^
[error] /path/to/ScalaTest/src/main/scala/app/Main.scala:60: could not find implicit value for parameter e: app.Enc[Int]
[error]   val e = implicitly[Enc[Int]]

好的,我理解这个输出。但是为什么它在隐式参数的情况下起作用?

【问题讨论】:

  • -Xlog-implicits 在这种情况下是你的朋友。它将显示为什么编译器会忽略您的可用实例。
  • @Haspemulator 我用这个选项添加了编译器输出。但是我还是不明白上下文绑定和隐式参数的区别。

标签: scala implicit context-bound


【解决方案1】:

我没有这方面的参考,但根据我的经验,对应于上下文绑定的隐式在之前搜索任何其他“显式”隐式参数;你的方法

implicit def test[I, T: Acceptable](implicit f: I => T): Enc[I] =
  Enc[I](f)

等价于

implicit def test2[I, T](implicit a: Acceptable[T], f: I => T): Enc[I] =
  Enc[I](f)

您可以轻松检查它也不起作用。为什么?从输出来看,编译器 first 似乎试图寻找隐含的 Acceptable[T],但由于歧义,此时它失败;此时它停止搜索其他任何内容。令人困惑的是错误消息,恕我直言,应该是“搜索Acceptable[T] 失败:模糊隐含”之类的东西。

为什么其他方法有效?因为隐式参数的顺序。编译器将首先搜索f: I => T,这很可能会将T 绑定到Int然后我们确实有一个唯一的Acceptable[Int] 隐含在范围内。一般

  • 我不会混合上下文边界和隐式参数
  • 隐式参数的顺序很重要,它们的排列应确保找到一个唯一地确定下一个

据我所知,所有这些都没有指定,取决于当前的实现;以上主要基于我调试隐含错误的经验。

【讨论】:

  • 多个隐式参数列表是可能的,但目前还不行——到目前为止,解决方案是Aux Pattern
  • 爱德华多,谢谢。你是完全正确的。我没有考虑隐含的顺序。
猜你喜欢
  • 2019-12-29
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-10-03
  • 2021-02-03
  • 1970-01-01
  • 2014-10-16
  • 2019-03-18
相关资源
最近更新 更多