我有这个代码:
trait Context {
implicit val e: Encoder
trait Encoder {
def write(): Unit = {
println("Test")
}
}
}
trait AsyncEncoders {
this: Context =>
class AsyncEncoder extends Encoder {
}
implicit val e = new AsyncEncoder()
}
class ConcreteContext extends Context with AsyncEncoders {
}
当我像这样使用它时(case 1):
object Main extends App {
implicit val c = new ConcreteContext()
import c._
implicitly[Encoder].write()
}
然后编译并打印Test
.
但是当我尝试在单例对象中调用相同的代码时(case 2):
object TestObject {
def apply()(implicit c: ConcreteContext): Unit = {
import c._
implicitly[Encoder].write()
}
}
object Main extends App {
implicit val c = new ConcreteContext()
TestObject()
}
编译失败并显示:
path/to/Main.scala:29: 找不到参数 e 的隐式值:c.Encoder
隐式[c.Encoder].write()
如果我改变(case 3):
implicit val e = new AsyncEncoder()
to
implicit val e: Encoder = new AsyncEncoder()
然后它会按预期编译并运行。
但由于某种原因,这对我来说是不能接受的。
为什么在上述情况下编译会失败?
我认为问题不在于你使用对象的事实,而在于你接受ConcreteContext
,作为参数:ConcreteContext.e
的类型是AsyncEncoder
, not Encoder
.
我多次观察到,当谈到 Scala 时,除非另有说明,否则最好将参数视为不变量(例如,如果不将 impl 类型转换为接口类型,macwire 经常会失败 - 但它并不是完全可预测的,大多数情况下)它工作的时间)。
正如您观察到的那样,将 e 类型显式设置为Encoder
会解决这个问题。改变也是如此ConcreteContext
to Context
。我的猜测是,这要么是编译器类型推断引擎的不变性问题,要么是限制问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)