Scala:导入如何防止发现隐含值?

时间:2016-11-20 21:43:32

标签: scala scope slick implicits shadowing

我可以使用调试隐式的建议:

我想使用隐式的x

type T
trait HasT {
  implicit def x: T = ...
}

但我还需要从某个包foo导入通配符。我尝试了两种不同的方式来介绍两者:

class UseT extends HasT {
  import foo._
  implicitly[T] // fails! "could not find implicit value"
  // use foo stuff
}

class UseT {
  object hasT extends HasT
  import hasT.x
  import foo._
  implicitly[T] // fails! "could not find implicit value"
}

两者都失败了"找不到" (不是"含糊不清的含义值")。

当通过继承或导入方法调用时可以访问隐式标识符x: T时,会发生这种情况。

我的解决方法是在导入之前将x重新绑定为隐式val。以下两项工作均为:

implicit val x2: T = implicitly[T]
import foo._
implicitly[T] // works!

implicit val x2: T = x
import foo._
implicitly[T] // works!

foo可能导致此行为的价值是什么?

我的第一个猜测是,foo中存在一些隐含的竞争,但如果它具有更高的优先级,则以下implicitly仍然有用,如果它是含糊不清的隐含的,我可以使用package hasT extends HasT; import hasT._。 d得到一个不同的错误。

编辑:Miles Sabin的猜测是正确的!我发现阴影是隐含的:timeColumnType。我仍然不完全理解这是如何工作的,因为Som Snytt观察到隐藏的阴影是通配符导入(优先级较低),而阴影是继承的(优先级最高的部分),所以我会离开这里的全部帖子都是后人。

收回由sabin提供的第二次猜测是implicit shadowing。我澄清了我的帖子以排除这种可能性。如果我尝试publishLocal,那么这种情况会与我的错误一致,但正如som-snytt指出的那样,这两种情况不会导致阴影。

在我的具体情况下,可以通过更改隐含的I尝试使用的名称来确认。
(这是错误的。在使用此测试进行验证时,我可能错过了reloadT。)

上下文:我实际上是在试图使用光滑的。上面的隐式import slick.driver.JdbcProfile class Custom { ... } // stored as `Long` in postgres trait ColumnTypes { val profile: JdbcProfile import profile.api._ // this is `foo` above type T = profile.BaseColumnType[Custom] implicit def customColumnType: T = MappedColumnType.base[Custom, Long](_.toLong, Custom.fromLong) } class DatabaseSchema(val profile: JdbcProfile) extends ColumnTypes { // `implicitly[T]` does not fail here. import profile.api._ // this is also `foo` above // `implicitly[T]` fails here, but it's needed for the following: class CustomTable(tag: Tag) extends Table[Custom](tag, "CUSTOMS") { // following fails unless I rebind customColumnType to a local implicit def custom = column[Custom]("CUSTOM") def * = custom } } 实际上是列类型映射:

api

foo / Some NuGet packages are missing from the solution. The packages need to be restored in order to build the dependency graph. Restore the packages before performing any operations 的类型为JdbcProfile.API。违规的隐含可能是here,但我不知道为什么。我会尝试阻止其中一些进口,看看我是否可以缩小它。

2 个答案:

答案 0 :(得分:8)

我认为foo最有可能包含名为x的定义。从({1}}导入(通配符)时,它会影响本地定义,

foo

答案 1 :(得分:2)

这显然是隐式搜索中的一个错误。

  

首先,符合条件的是可以访问的所有标识符x   没有前缀的方法调用的点,表示隐式   定义或隐含参数。因此,合格的标识符可以   是本地名称,或封闭模板的成员,或者它可能是   通过import子句可以在没有前缀的情况下访问它。

在示例中,未加前缀的x表示继承的符号。如果没有前缀,则无法访问X.x

隐式搜索正在破坏导入。

$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X { def x: Int = 42 }

trait T { def x: Int = 17 }

object Y extends T {
  import X._
  def f = x
}

// Exiting paste mode, now interpreting.

defined object X
defined trait T
defined object Y

scala> Y.f
res0: Int = 17

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X { implicit def x: Int = 42 }

trait T { implicit def x: Int = 17 }

object Y extends T {
  import X._
  def f: Int = implicitly[Int]
}

// Exiting paste mode, now interpreting.

<pastie>:19: error: could not find implicit value for parameter e: Int
         def f: Int = implicitly[Int]
                                ^

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X { implicit def x: Int = 42 }

trait T { implicit def x: Int = 17 }

object Y extends T {
  import X.{x => _, _}          // avoids bug, but is redundant
  def f: Int = implicitly[Int]
}

// Exiting paste mode, now interpreting.

defined object X
defined trait T
defined object Y

scala> 

使用REPL的另一个示例是这样的:

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X { def x: Int = 42 }
object Y { implicit def x: Int = 17 }
object Z {
  import Y.x
  def f = {
    import X._
    x
  }
}

// Exiting paste mode, now interpreting.

<pastie>:19: error: reference to x is ambiguous;
it is imported twice in the same scope by
import X._
and import Y.x
           x
           ^

x根本不可用,并且隐式被正确排除。

只是为了确认:

$ scala -Xlog-implicits
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.

scala> :pa
// Entering paste mode (ctrl-D to finish)

object X { implicit def x: Int = 42 }

trait T { implicit def x: Int = 17 }

object Y extends T {
  import X._
  def f: Int = implicitly[Int]
}

// Exiting paste mode, now interpreting.

<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
         def f: Int = implicitly[Int]
                                ^
<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
         def f: Int = implicitly[Int]
                                ^
<console>:17: error: could not find implicit value for parameter e: Int
         def f: Int = implicitly[Int]
                                ^

scala> 

可能https://issues.scala-lang.org/browse/SI-9208