scala - Scala 中嵌套类型的模式匹配

标签 scala pattern-matching nested-class case-class

我正在尝试在 Scala 中实现一些有效的枚举。我想使用 case 类来做到这一点,以便编译器能够检测任何非详尽的模式匹配。

这在非常基本的形式下工作正常,例如:

sealed abstract class HorizontalAlignment
case object Left extends HorizontalAlignment
case object Right extends HorizontalAlignment
case object Center extends HorizontalAlignment
case object AsIs extends HorizontalAlignment
...
def test (x : HorizontalAlignment) = 
  x match {
    case Left => ...
    ...  
  } 

然而,这并不理想,因为 case 对象的名称很容易发生冲突:
sealed abstract class HorizontalAlignment
case object Left extends HorizontalAlignment
case object Right extends HorizontalAlignment
case object Center extends HorizontalAlignment
case object AsIs extends HorizontalAlignment

sealed abstract class VerticalAlignment
case object Top extends VerticalAlignment
case object Bottom extends VerticalAlignment
case object Center extends VerticalAlignment
case object AsIs extends VerticalAlignment

// "Center" and "AsIs" clash

显而易见的解决方案是将 case 对象放入单独的命名空间:
sealed abstract class HorizontalAlignment {
  case object Left extends HorizontalAlignment
  case object Right extends HorizontalAlignment
  case object Center extends HorizontalAlignment
  case object AsIs extends HorizontalAlignment
}

sealed abstract class VerticalAlignment {
  case object Top extends VerticalAlignment
  case object Bottom extends VerticalAlignment
  case object Center extends VerticalAlignment
  case object AsIs extends VerticalAlignment
}

但是如何在匹配块中引用这些类呢?

它们不能用 Java 样式的点引用:
def test (x : HorizontalAlignment) = 
x match {
  case HorizontalAlignment.Left => 0  //  error: not found: value HorizontalAlignment
}

“#”符号似乎也不起作用:
def test (x : HorizontalAlignment) = 
x match {
  case HorizontalAlignment#Left => 0 // error: '=>' expected but '#' found 
}

而且这个表格也不起作用:
def test (x : HorizontalAlignment) = 
x match {
  case _ : HorizontalAlignment#Left => 0  // error: type Left is not a member of Test.HorizontalAlignment
}

这是有道理的,因为“左”在这种情况下是一个实例而不是一个类型,我怀疑有一种简单的方法来引用该类型。我最接近实现这一目标的是:
sealed abstract class HorizontalAlignment {
  case class Left extends HorizontalAlignment
  case class Right extends HorizontalAlignment
  case class Center extends HorizontalAlignment
  case class AsIs extends HorizontalAlignment

  object Left
  object Right
  object Center
  object AsIs

}

但是,尽管这使得 match 块编译得很好,但我找不到任何方法来实际引用这些对象,例如将此“枚举”的成员传递给函数。这是因为 Horizo​​ntalAlignment 是一种类型而不是对象,因此不可能使用字段访问来引用其中一个嵌套对象,另一方面,这些对象不是类型,因此不可能使用“#“象征。

有没有办法从类外部引用嵌套在类中的对象?

编辑

到目前为止,我发现包对象是解决这个问题的最好方法。
package object HorizontalAlignment  {
  sealed abstract class HorizontalAlignment
  case object Left extends HorizontalAlignment
  case object Right extends HorizontalAlignment
  case object Center extends HorizontalAlignment
  case object AsIs extends HorizontalAlignment
}

package object VerticalAlignment {
  sealed abstract class VerticalAlignment 
  case object Top extends VerticalAlignment 
  case object Bottom extends VerticalAlignment 
  case object Center extends VerticalAlignment 
  case object AsIs extends VerticalAlignment 
}


object Test {
  import HorizontalAlignment.HorizontalAlignment
  import VerticalAlignment.VerticalAlignment 

  def test (x : HorizontalAlignment, y : VerticalAlignment) =  {
    x match {
      case HorizontalAlignment.Left => ...
      ...
    }

    y match {
      case VerticalAlignment.Top => ...
      ...
    }
  }

  def testTest = test (HorizongalAlignment.Left, VerticalAlignment.Top)

}

但是,上述问题(访问类中的嵌套对象)仍然存在。

最佳答案

你不必使用包对象,它可能有一些额外的不受欢迎的语义:常规的旧伴随对象也一样好:

sealed trait HorizontalAlignment
object HorizontalAlignment {
  case object Left extends HorizontalAlignment
  case object Right extends HorizontalAlignment
  case object Center extends HorizontalAlignment
  case object AsIs extends HorizontalAlignment
}

scala> def test (x : HorizontalAlignment) = x match {
     |   case HorizontalAlignment.Left => "got left"
     | }

scala> test(HorizontalAlignment.Left)
res0: java.lang.String = got left

您遇到的问题是,由于 Horizo​​ntalAlignment 是一个抽象类,因此没有要取消引用的 Horizo​​ntalAlignment 实例。使用原始命名空间公式,您需要实例化一个 Horizo​​ntalAlignment 实例,并且内部对象将特定于该实例。但是,由于 Horizo​​ntalAlignment 是密封的,因此除了定义它的编译单元之外,您无法在任何其他编译单元中创建这样的实例,因此您的枚举值实际上永远无法通过任何方式获得。

与 Java 不同的是,没有与类相关联的“静态命名空间”;要获得等价物,您必须使用伴随对象。

关于scala - Scala 中嵌套类型的模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5765311/

相关文章:

Java 注释 - javac 编译器错误?

scala - 如何在 Scala 中打印扩展宏?

java - 为什么 map 变换是窄的?

types - 在火柴臂中创建闭包

python - Python 中的嵌套类

c# - 将嵌套 XML 中的父对象获取到 Linq

spring - 如何让 Spring 连接我的 JmsComponent

scala - 使用 Shapeless 进行域类和灵活生成的案例类转换

string - 在字符串 Lua 中插入 "-"

java - Scala 编译器不使用 case 类的 unapply 方法进行模式匹配,这是为什么呢?