Iva*_*kov 4 scala pattern-matching nested-class case-class
我试图在Scala中实现一些有效的枚举.我想使用案例类来做到这一点,以便编译器能够检测任何非详尽的模式匹配.
这在基本形式下工作正常,例如:
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 => ...
...
}
Run Code Online (Sandbox Code Playgroud)
但是这并不理想,因为案例对象的名称很容易发生冲突:
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
Run Code Online (Sandbox Code Playgroud)
显而易见的解决方案是将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
}
Run Code Online (Sandbox Code Playgroud)
但是如何在匹配块中引用这些类?
它们不能用Java样式的点引用:
def test (x : HorizontalAlignment) =
x match {
case HorizontalAlignment.Left => 0 // error: not found: value HorizontalAlignment
}
Run Code Online (Sandbox Code Playgroud)
"#"符号似乎也不起作用:
def test (x : HorizontalAlignment) =
x match {
case HorizontalAlignment#Left => 0 // error: '=>' expected but '#' found
}
Run Code Online (Sandbox Code Playgroud)
这种形式也不起作用:
def test (x : HorizontalAlignment) =
x match {
case _ : HorizontalAlignment#Left => 0 // error: type Left is not a member of Test.HorizontalAlignment
}
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为"Left"在这种情况下是一个实例而不是一个类型,我怀疑有一种简单的方法来引用该类型.我能达到的最接近的是:
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
Run Code Online (Sandbox Code Playgroud)
}
但是虽然这使匹配块编译正常,但我找不到任何方法来实际引用这些对象,例如将此"枚举"的成员传递给函数.这是因为HorizontalAlignment是一个类型而不是一个对象,因此不可能使用字段访问来引用其中一个嵌套对象,另一方面,这些对象不是类型,所以不可能使用它来引用它们. "#"符号.
有没有办法从类外部引用嵌套在类中的对象?
编辑
到目前为止,我发现包对象是解决此问题的最佳方法.
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)
Run Code Online (Sandbox Code Playgroud)
}
但是,上述问题(对类中嵌套对象的访问)仍然存在.
Kri*_*mbe 11
您不必使用包对象,它可能具有一些其他不合需要的语义:常规的旧伴随对象也同样好:
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
Run Code Online (Sandbox Code Playgroud)
您遇到的问题是,由于HorizontalAlignment是一个抽象类,因此没有要取消引用的HorizontalAlignment实例.使用原始的命名空间公式,您需要实例化HorizontalAlignment实例,并且内部对象将特定于该实例.但是,由于HorizontalAlignment是密封的,因此您无法在任何其他编译单元中创建此类实例而不是定义它的实例,因此实际上永远无法通过任何方式获取枚举值.
与Java不同,没有与类关联的"静态命名空间"; 为了获得等价物,你必须使用一个伴侣对象.