我有这段代码:
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 {
}
当我像这样使用它时(案例1 ):
object Main extends App {
implicit val c = new ConcreteContext()
import c._
implicitly[Encoder].write()
}
然后它编译并打印Test
。
但是当我尝试在singleton对象中调用相同的代码时( 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()
如果我改变了(案例3 ):
implicit val e = new AsyncEncoder()
到
implicit val e: Encoder = new AsyncEncoder()
然后它按预期编译并运行。
但由于某些原因,这对我来说是不可接受的。
为什么在上述情况下编译失败?
答案 0 :(得分:0)
我认为问题不在于您使用对象,而在于您接受ConcreteContext
作为参数:ConcreteContext.e
的类型是AsyncEncoder
,而不是{ {1}}。
我经常观察到,当谈到Scala时,除非另有说明,否则最好将参数视为不变量(例如,如果不将impl类型转换为接口类型,macwire通常会失败 - 尽管它不是完全可预测的,大部分时间都有效。)
正如您观察到将{e}类型明确设置为Encoder
可以解决问题。因此会将Encoder
更改为ConcreteContext
。我的猜测是,这是编译器类型推理引擎的不变性或限制问题。
答案 1 :(得分:0)
正如评论中所述,Scala 2.12.0中没有问题。
对于Scala 2.11.8,假设Encoder
只有一个方法,我使用了以下解决方法:
trait Context {
implicit val e: Encoder
type BaseEncoder = () => Unit
type Encoder <: BaseEncoder
}
trait AsyncEncoders {
this: Context =>
type Encoder = AsyncEncoder
class AsyncEncoder extends BaseEncoder {
override def apply(): Unit = {
println("Test")
}
}
implicit val e = new AsyncEncoder()
}
class ConcreteContext extends Context with AsyncEncoders {
}
object TestObject {
def apply()(implicit c: ConcreteContext): Unit = {
import c._
implicitly[Encoder].apply()
}
}
object Main extends App {
implicit val c = new ConcreteContext()
TestObject()
}