Scala:隐式查找类型 class 路径相关类型的实例
Scala: implicit lookup of type class instance for path-dependent type
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
并且隐式查找成功。但这对我的用例来说并不适用。
有没有其他方法可以引导隐式查找?我是否丢失了类型信息,因为我缺少类型优化之类的?
这无法实现,因为 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))
}
推断类型一次一个步骤。此外,我看不出有任何理由在这里(或者,就此而言,在任何地方;尽管这是一个不同的问题)使用依赖于值的类型。
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))
}
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
并且隐式查找成功。但这对我的用例来说并不适用。
有没有其他方法可以引导隐式查找?我是否丢失了类型信息,因为我缺少类型优化之类的?
这无法实现,因为 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))
}
推断类型一次一个步骤。此外,我看不出有任何理由在这里(或者,就此而言,在任何地方;尽管这是一个不同的问题)使用依赖于值的类型。
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))
}