具有类型成员的案例对象上的模式匹配

sik*_*kor 9 generics types scala pattern-matching type-members

Scala有一个很好的功能来推断模式匹配中的类型参数.它还检查模式匹配穷举.例如:

sealed trait PField[T]

case object PField1 extends PField[String]

case object PField2 extends PField[Int]

def getValue[X](f: PField[X]): X = f match {
  case PField1 => "aaa"
  case PField2 => 123
}
Run Code Online (Sandbox Code Playgroud)

是否可以实现相同但使用类型成员而不是类型参数?

sealed trait Field {
  type T
}

case object Field1 extends Field {
  type T = String
}

case object Field2 extends Field {
  type T = Int
}
Run Code Online (Sandbox Code Playgroud)

以下解决方案不起作用(在Scala 2.12.6中测试):

//No exhaustiveness check
def getValue[X](f: Field {type T = X}): X = f match {
  case Field1 => "aaa"
  //    case Field2 => 123
}

//casting needed
def getValue2[X](f: Field {type T = X}): X = (f: Field) match {
  case Field1 => "aaa".asInstanceOf[X]
  case Field2 => 123.asInstanceOf[X]
}

type Generified[X] = Field {type T = X}

//No exhaustiveness check
def getValue3[X](f: Generified[X]): X = f match {
  case Field1 => "aaa"
  //    case Field2 => 123
}
Run Code Online (Sandbox Code Playgroud)

在我的情况下,类型参数确实存在问题,因为我有很多字段的子层次结构,每个层次结构都有一些类型类.我无法将所有必需的依赖项放在case对象中,因为它们是在瘦JAR中导出到客户端的.

sik*_*kor 3

该解决方案是@Andrey Tyukin 发布的解决方案的简化版本。他表示

对于 Field3 类型的任何两个值 a、b,它不成立 aT = bT。

这意味着,要进行详尽的模式匹配,必须忽略类型成员。因此,为了兼具详尽性和类型推断,我们需要带有类型参数的密封层次结构。

他建议创建单独的案例类层次结构,并在它们上而不是在主层次结构上进行模式匹配。然而,就我而言,它可以简化:我创建了带有类型参数的新密封特征,但相同的情况对象用于模式匹配(“唯一保证”保存在对象本身中)。这是最终的解决方案:

sealed trait Field {
  type T
  def ug: TField[T]
}

sealed trait TField[G] extends Field {
  type T = G
  def ug: TField[T] = this
}

case object Field1 extends TField[String]
case object Field2 extends TField[Int]

def getValue[X](f: Field {type T = X}): X = (f.ug: TField[X]) match {
  case Field1 => "abc"
  case Field2 => 123
}
Run Code Online (Sandbox Code Playgroud)

因此,我可以使用Field特征来定义类型类,而无需进入更高种类的类型并切换到TField[G]模式匹配。