用提取器替换案例类继承,保留Scala中的穷举检查 [英] Replacing case class inheritance with extractors preserving exhaustiveness checks in Scala

查看:142
本文介绍了用提取器替换案例类继承,保留Scala中的穷举检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的类层次结构,它表示一个类似于图形的结构,它使用case类实现了几个不同类型的顶点:

I have a simple class hierarchy that represents a graph-like structure with several distinct types of vertexes implemented using case classes:

sealed trait Node

sealed abstract case class Vertex extends Node
case class Arc extends Node

case class VertexType1 (val a:Int) extends Vertex
case class VertexType2 (val b:Int) extends Vertex

这允许我写这样的匹配块:

This allows me to write match blocks like this:

def test (x: Node) = x match {
  case _ : Arc => "got arc"
  case _ : Vertex => "got vertex"
}

或者像这样:

def test (x: Node) = x match {
  case _ : Arc => "got arc"
  case c : Vertex => c match {
    case _ : VertexType1(a) => "got type 1 vertex " + a
    case _ : VertexType2(a) => "got type 2 vertex " + a
  }
}

注意这个实现具有以下属性:

Note that this implementation has the following properties:

1)它允许写入区分弧和顶点的匹配块,但不能在特定顶点类型之间进行区分,但也可以匹配区分区块顶点类型。

1) It allows writing match blocks that differentiate between arcs and vertices, but not between specific vertex types, but also match blocks that do differentiate between vertex types.

2)在特定于顶点类型和非顶点类型的匹配块中,检查模式匹配的详尽性。

2) In both vertex-type-specific and non-vertex-type-specific match blocks the exhaustiveness of pattern matching is checked.

但是,不推荐使用case类继承,编译器建议使用提取器来支持非叶节点上的匹配(即,在上面的例子中,区分弧和顶点,但不是在顶点类型之间)。

However, inheritance from case classes is deprecated, and the compiler suggests to use extractors instead to support matching on non-leaf nodes (i.e., in the above example, to differentiate between arcs and vertices, but not between vertex types).

问题:是否可以在不使用案例类继承的情况下实现类似的类层次结构,但仍然在上面显示的两种用例中都由编译器执行模式穷举检查?

The question: is it possible to implement a similar class hierarchy without using case class inheritance, but still having pattern exhaustiveness checks performed by the compiler in both use cases shown above?

编辑:我在VertexType类中添加了一个构造函数参数,因此不会仅对类型执行匹配。

EDIT: I have added a constructor parameter to the VertexType classes so that the match is not performed only on types.

我目前没有案例类的实现如下:

My current implementation without the case classes is as follows:

sealed trait Node

sealed abstract class Vertex extends Node
class Arc extends Node

class VertexType1 (val a:Int) extends Vertex
class VertexType2 (val b:Int) extends Vertex

object VertexType1 {
  def unapply (x : VertexType1) : Some[Int] = Some(x.a)
}

object VertexType2 {
  def unapply (x : VertexType2) : Some[Int] = Some(x.b)
}

测试代码:

def test (x: Node) = x match {
  case _ : Arc => "got arc" 
  case v : Vertex => v match {
    case VertexType1(a) => "got vertex type 1 " + a 
  }
}

我期待一个关于第二个块中非穷尽匹配的警告(VertexType2从不匹配),但没有一个。

I expect a warning about non-exhaustive match in the second block (VertexType2 is never matched), but there isn't one.

实际上,在2.9.0之前的Scala编译器-RC3产生一个我希望看到的警告,但是以RC3开头的版本(包括2.9.0和2.9.0-1)没有,这是相当混乱的。

推荐答案

提取器使您可以在模式匹配中使用它,就像scala中的case类一样,但它们在使用case修饰符时没有其他标准实现。
但是这些额外的实现(尤其是equals的实现)使得case类继承变得危险,因此它被弃用了。

extractors give you the possibility to use it in pattern matching like case classes in scala, but they don´t have other standard implementations you get when using the case modifier. But hust these extra implementation(especially the implementation of equals) is what makes case class inheritance dangerous and so it got deprecated.

然而,密封类是正交的功能,您可以使用它们,无论您是否有案例类或提取器。通过使用提取器,您无法动态获得标准实现,但因此您可以继承提取器 - 它们只是具有unapply和/或unapplySeq方法的普通类。

However sealed classes are an orthogonal feature and you can use them whether or not you have a case class or an extractor. By using extractors you don´t get standard implementations on the fly but thus you can have inheritance of extractors - they are simply normal classes with an unapply and/or unapplySeq method.

您在示例中所做的事情在类型上称为模式匹配。如果您只想这样做,则不需要案例类和提取器。你可以用你想要的每个课程。所以你可以简单地删除case修饰符。

What You´ve done in your example is called pattern-matching on types. If you only want to do this, you don´t need case classes neither extractors. You can do it with every class you want. So you can simply remove the case modifier.

所以得出结论:模式的详尽性是通过密封的类hirachies实现的。模式匹配是通过提取器和案例类实现的,后者只是一个提取器,具有吸引人的常用函数的标准实现。
我希望这有帮助。

So to conclude: exhaustiveness of pattern is achieved by sealed class hirachies. Pattern matching is achieved by extractors and case classes of what the latter is just an extractor with appealing standard implementations of frequently used functions. I hope this helped.

这篇关于用提取器替换案例类继承,保留Scala中的穷举检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆