首页 > 解决方案 > 如何在 Scala 类型类中定义与路径无关的辅助类型?

问题描述

让我们有一个类型类,它根据类型定义了更多要使用的类型:

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

因为类型是依赖于路径的,所以编译器在尝试使用它时会抱怨,错误是:

类型不匹配;

找到:字符('X')

必需: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)
}

缺点是在需要提供所有类型参数时调用类型类:

val ops = implicitly[Container[String, Char]]

有没有办法在类型类中定义类型,以便它们可以用作路径无关?

标签: scalatypeclasspath-dependent-type

解决方案


你只是要求

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

带有辅助模式的东西变成了

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

推荐阅读