2
object Test {

  trait Foo

  trait TC[A]

  object TC {
    implicit def tc1[F <: Foo] = new TC[F] {}
    implicit def tc2[F1 <: Foo, F2 <: Foo] = new TC[(F1, F2)] {}
  }   

  object Bar {
    trait X
    val c = new Foo with X
    def bar[A](a: this.type => A)(implicit tc: TC[A]) = 1
  }

  Bar bar (_.c)

  Bar bar (b => (b.c, b.c))
}

最后一行给出编译器错误“找不到参数 tc 的隐式值...”。

现在:移到trait X外面object Bar使它工作。

倒数第二行适用于这两种情况。

这有什么好的理由,和/或是否可以在不将特征移出对象的情况下使其工作?

4

1 回答 1

2

这不会是一个完整的答案(并且包含大量猜测),但是鉴于您直到现在都没有得到任何答案,我想这总比没有好。

似乎问题在于编译器将Xinnew Foo with X视为路径依赖类型,即使我们处于对象定义而不是类中。因此,编译器会A = (Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }在第二次调用中推断bar. 这要求编译器找到 type 的隐式值TC[(Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }],并且显然tc2不合适(我对 scala 类型系统的极端情况不够熟悉,无法确定是否存在真正的不兼容,或者编译器是否没有线索)

【炒作模式】

路径相关类型处理的问题对我来说就像一个错误(或者至少是一个未指定的奇怪)。我认为罪魁祸首是对象的主体被编译为与类没有什么不同,然后以某种方式被制成单例对象,这意味着它new Foo with X实际上被视为new Foo with this.X而不是new Foo with Bar.X,因此被视为路径依赖类型(甚至虽然他们应该恕我直言在这种情况下表示完全相同的东西)。

[/推测模式]

现在对于奇怪的部分(这也是您要求的解决方法):转动这个:

val c = new Foo with X

进入这个:

val c = new Foo with Bar.X

实际上修复了编译。据我了解,这是因为通过显式指定Bar我们强制编译器识别这Bar.X是一个稳定的路径,这解决了路径依赖类型的问题。

现在,真正的解决办法当然是按照你的建议真正搬到X外面去。Bar它有效且无痛,那么为什么不这样做呢?

于 2013-04-02T23:26:05.323 回答