trait Encoder[From, To] {
def encode(x: From): To
}
object Encoder {
implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] {
def encode(x: Thing): String = x.toString
}
}
trait Config {
type Repr
}
class MyConfig extends Config { type Repr = String }
//class ConcreteConfig { type Repr = String }
class Api[T](val config: Config) {
def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {}
}
case class Thing(a: Int)
object Test extends App {
import Encoder._
val api = new Api[Thing](new MyConfig)
api.doSomething(Thing(42))
}
对api.doSomething
的调用无法编译:
could not find implicit value for parameter encoder: Encoder[Thing,Test.api.config.Repr]
如果我更改class Api[T]
构造函数的签名以使其需要ConcreteConfig
,那么编译器可以告诉config.Repr == String
并且隐式查找成功。但这对我的用例来说并不适用。
还有其他方法来指导隐式查找吗?我丢失了类型信息,因为我错过了类型细化或什么?
答案 0 :(得分:0)
由于config.Repr不是稳定路径,因此无法实现。编译器无法确定config.Repr = String,即使config的运行时值为MyConfig类型
只有当您可以在Api中提供具体的配置实例作为类型参数时才会起作用,这将告诉编译器Repr的确切类型:
class Api[T, C <: Config](val config: C) {
def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {}
}
object Test extends App {
import Encoder._
val api = new Api[Thing, MyConfig](new MyConfig)
api.doSomething(Thing(42))
}
答案 1 :(得分:0)
一次推断类型一步。此外,我没有看到在这里使用价值相关类型的任何理由(或者,就此而言,在任何地方;但这是一个不同的问题)。
trait Encoder[From, To] {
def encode(x: From): To
}
object Encoder {
implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] {
def encode(x: Thing): String = x.toString
}
}
trait Config {
type Repr
}
class MyConfig extends Config { type Repr = String }
// class ConcreteConfig { type Repr = String }
case class Api[T, C <: Config](val config: C) {
def doSomething(value: T)(implicit encoder: Encoder[T, C#Repr]): Unit = ()
}
case class ApiFor[T]() {
def withConfig[C <: Config](config: C): Api[T,C] = Api(config)
}
case class Thing(a: Int)
object Test extends App {
import Encoder._
val api = ApiFor[Thing] withConfig new MyConfig
// compiles!
api.doSomething(Thing(42))
}