首页 > 解决方案 > 为什么提取和分配单个元组值会导致递归隐式搜索?

问题描述

这是产生此错误的代码:

构建.sbt

scalaVersion := "2.11.7"

libraryDependencies ++= Seq(
  "ai.x" %% "safe" % "0.1.0"

)

scalacOptions := Seq("-Ytyper-debug") // Only add this if you want to see a bunch of stuff

测试.scala

import ai.x.safe._

package object foo {
    final implicit val (enc, dec) = {
        ("x" === "y") -> 0
    }
}

试图编译它会导致这个错误:

[info] Compiling 1 Scala source to /tmp/test/target/scala-2.11/classes...
[error] /tmp/test/test.scala:4: recursive value x$1 needs type
[error]     final implicit val (enc, dec) = {
[error]                         ^
[error] one error found

在完全调试模式下,我可以看到它正在尝试解析===,编译器正在查看当前的隐式以确定是否有任何匹配。由于(enc, dec)是隐式的,它似乎也使用它们,因此它尝试输入它们,导致编译器抱怨这种隐式递归。

|    |    |    |    |    |-- "x".$eq$eq$eq("y") EXPRmode-POLYmode-QUALmode (silent: value x$1 in package) 
|    |    |    |    |    |    |-- "x".$eq$eq$eq BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value x$1 in package) 
|    |    |    |    |    |    |    |-- "x" EXPRmode-POLYmode-QUALmode (silent: value x$1 in package) 
|    |    |    |    |    |    |    |    \-> String("x")
|    |    |    |    |    |    |    |-- x$1._1 EXPRmode (site: value enc  in package) 
|    |    |    |    |    |    |    |    |-- x$1 EXPRmode-POLYmode-QUALmode (site: value enc  in package) 
|    |    |    |    |    |    |    |    |    caught scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving value x$1: while typing x$1
[error] /tmp/test/test.scala:4: recursive value x$1 needs type
[error]     final implicit val (enc, dec) = {
[error]                         ^
|    |    |    |    |    |    |    |    |    \-> <error>
|    |    |    |    |    |    |    |    \-> <error>
|    |    |    |    |    |    |    |-- x$1._2 EXPRmode (site: value dec  in package) 
|    |    |    |    |    |    |    |    |-- x$1 EXPRmode-POLYmode-QUALmode (site: value dec  in package) 
|    |    |    |    |    |    |    |    |    \-> <error>
|    |    |    |    |    |    |    |    \-> <error>
|    |    |    |    |    |    |    |-- SafeEquals BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value x$1 in package) implicits disabled
|    |    |    |    |    |    |    |    |-- ai.x.safe.`package` EXPRmode-POLYmode-QUALmode (silent: value x$1 in package) implicits disabled
|    |    |    |    |    |    |    |    |    \-> ai.x.safe.type
|    |    |    |    |    |    |    |    \-> ai.x.safe.SafeEquals.type <and> [T](l: T)ai.x.safe.SafeEquals[T]
|    |    |    |    |    |    |    solving for (T: ?T)
|    |    |    |    |    |    |    solving for (T: ?T)
|    |    |    |    |    |    |    solving for (T: ?T)
|    |    |    |    |    |    |    [adapt] SafeEquals adapted to [T](l: T)ai.x.safe.package.SafeEquals[T] based on pt String("x") => ?{def ===: ?}
|    |    |    |    |    |    |    |-- [T](l: T)ai.x.safe.package.SafeEquals[T] EXPRmode-POLYmode-QUALmode (silent: value x$1 in package) 
|    |    |    |    |    |    |    |    \-> ai.x.safe.package.SafeEquals[String]
|    |    |    |    |    |    |    |-- ai.x.safe.`package`.SafeEquals[String]("x").$eq$eq$eq BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value x$1 in package) 
|    |    |    |    |    |    |    |    \-> (r: String)Boolean
|    |    |    |    |    |    |    \-> (r: String)Boolean
|    |    |    |    |    |    |-- "y" : pt=String BYVALmode-EXPRmode (silent: value x$1 in package) 
|    |    |    |    |    |    |    \-> String("y")
|    |    |    |    |    |    \-> Boolean

我当然可以通过执行以下操作使其编译:

final val (x,y) = {
    ("x" === "y") -> 0
}
implicit val (f,b) = (x,y)

由于在定义主体时不存在隐式,因此在定位from可以应用并使代码正常工作{}时,它们不会干扰编译器的隐式搜索。现在我对此并没有真正的问题,因为它确实有意义,因为人们可以定义惰性递归序列化器和其他可以毫无问题地使用自身的隐式事物。因此,编译器当然应该查看被定义为可能的应用程序以使某些东西工作的隐式。===SafeEqualsString

但对我来说奇怪的是,如果您在分配期间不直接提取元组,这会起作用:

final implicit val tuple = {
    ("x" === "y") -> 0
}

显然这不是我想要做的,因为我希望元组中的两件事都是隐式的(在我的真实情况下,它是来自 circe 的编码器/解码器对)。但是对我来说很奇怪的是,使用(我相信是)Tuple2 的提取器会导致这个编译器错误,并搜索隐式。谁能告诉我为什么会发生这种情况或导致这种行为的原因是什么?我很想知道更多关于我在调试输出中看到的内容。为什么解析元组内部每个事物的类型会导致编译器错误,但解析整个元组的类型不会导致任何问题?

标签: scalaimplicits

解决方案


推荐阅读