如何在 Scala 类型 class 中定义与路径无关的辅助类型?
How to define a helper types to be path-independent in a Scala type class?
让我们有一个类型 class,它根据类型定义了更多类型:
trait Container[T] {
type Elem
def get(c: T, i: Int): Elem
def set(c: String, i: Int, v: Elem): T
}
implicit object StringContainer extends Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
val ops = implicitly[Container[String]]
ops.set("ABC", 1, ops.get("ABC", 1)) // works
ops.set("ABC", 1, 'X') // type mismatch; found : Char('X') required: ops.Elem
因为类型依赖于路径,编译器在尝试使用它时会报错,错误是:
type mismatch;
found : Char('X')
required: ops.Elem
你我都知道 ops.Elem
是 Char
。我当前的解决方法是使用 Elem
作为类型参数:
trait Container[T, Elem] {
def get(c: T, i: Int): Elem
def set(c: String, i: Int, v: Elem): T
}
implicit object StringContainer extends Container[String, Char] {
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
缺点是在需要时调用类型 class 需要提供所有类型参数:
val ops = implicitly[Container[String, Char]]
是否有一些方法可以在 type-class 中定义类型,以便它们可以用作路径无关的?
您只需要
Container[String]
而不是
Container[String] { type Elem = Char }
尝试类型优化
object Container {
implicit val strContainer: Container[String] { type Elem = Char } = new Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
}
val ops = implicitly[Container[String] { type Elem = Char }]
ops.set("ABC", 1, 'X') // ok
Aux 模式变成类似
object Container {
type Aux[T,Elem0] = Container[T] { type Elem = Elem0 }
implicit val strContainer: Aux[String, Char] = new Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
}
val ops = implicitly[Container.Aux[String,Char]]
ops.set("ABC", 1, 'X') // ok
让我们有一个类型 class,它根据类型定义了更多类型:
trait Container[T] {
type Elem
def get(c: T, i: Int): Elem
def set(c: String, i: Int, v: Elem): T
}
implicit object StringContainer extends Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
val ops = implicitly[Container[String]]
ops.set("ABC", 1, ops.get("ABC", 1)) // works
ops.set("ABC", 1, 'X') // type mismatch; found : Char('X') required: ops.Elem
因为类型依赖于路径,编译器在尝试使用它时会报错,错误是:
type mismatch;
found : Char('X')
required: ops.Elem
你我都知道 ops.Elem
是 Char
。我当前的解决方法是使用 Elem
作为类型参数:
trait Container[T, Elem] {
def get(c: T, i: Int): Elem
def set(c: String, i: Int, v: Elem): T
}
implicit object StringContainer extends Container[String, Char] {
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
缺点是在需要时调用类型 class 需要提供所有类型参数:
val ops = implicitly[Container[String, Char]]
是否有一些方法可以在 type-class 中定义类型,以便它们可以用作路径无关的?
您只需要
Container[String]
而不是
Container[String] { type Elem = Char }
尝试类型优化
object Container {
implicit val strContainer: Container[String] { type Elem = Char } = new Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
}
val ops = implicitly[Container[String] { type Elem = Char }]
ops.set("ABC", 1, 'X') // ok
Aux 模式变成类似
object Container {
type Aux[T,Elem0] = Container[T] { type Elem = Elem0 }
implicit val strContainer: Aux[String, Char] = new Container[String] {
type Elem = Char
def get(c: String, i: Int) = c(i)
def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}
}
val ops = implicitly[Container.Aux[String,Char]]
ops.set("ABC", 1, 'X') // ok