Scala中的嵌套与展平模式匹配

Posted

技术标签:

【中文标题】Scala中的嵌套与展平模式匹配【英文标题】:Nested vs flattened pattern match in Scala 【发布时间】:2019-06-15 17:49:18 【问题描述】:

假设我在 Scala 中有 n 个值,名为 v1v2, ..., vi, ..., vn 类型 Tij 对于不同的i 不一定是不同的类型。我想使用自定义逻辑对 n 值进行模式匹配。

一种方法是嵌套所有可能性,以防我需要详尽无遗(为了这个示例,我需要这样做,否则我可以使用占位符 mag_c)并且我无法合并分支(为了这个例子,我不能因为每个自定义逻辑都是唯一的):

v1 match 
  case x1: T11 => v2 match 
    case x2: T21 => v3 match 
      ...
        case xn_1: Tn_11 => vn match 
          case xn: Tn1 => // Custom logic 1.
          case xn: Tn2 => // Custom logic 2.
          ...
          case xn: Tnk => // I am already laughing, but I have to write it down: 
                          // Custom logic k.
        
        ...     
      ...
    
    case x2: T22 => v3 match 
      // I guess you get the point. 
    
    ...
  case x1: T12 => v2 match 
    // And so on until exhaustion in every meaning of the word.
  
  ... // These three dots are needed here. Now I feel whole.      

另一种选择是将整个该死的东西弄平:

(v1, v2, ..., vn) match 
    case (x1: T11, x2: T21, ... xn: Tn1) => // Custom logic 1.
    case (x1: T11, x2: T21, ... xn: Tn2) => // Custom logic 1.
    ...
    case (x1: T11, x2: T21, ... xn: Tnk) => // Custom logic k (with a hearthy chuckle).
    ... // Three dots saving my soul and my finger joints.

虽然嵌套版本避免了重复输入,但当 n 很高(而我们不是)时,由于缩进溢出可能导致代码难以阅读。

另一方面,扁平化版本包含大量重复代码,但更容易解释。

此外,嵌套版本似乎更高效,因为对 xi 的检查最多发生一次,每个类型 Tij(但也许我不应该关心JVM可以将其全部优化掉的东西,我不想成为all evil)。

哪一个是惯用的 Scala 代码,因此值得推荐?两个版本之间有性能差异吗?

【问题讨论】:

从性能上看嵌套版本更好。从可读性的角度来看,哪个更好取决于您的个人喜好,没有明确的答案。 @talex 性能更高的嵌套模式匹配不会使对元组使用扁平化模式无效,或者在 n 较小的情况下,差异不明显吗?在高 n 的情况下,扁平版本似乎更具可读性,因为我不必回忆(回滚)哪个值是什么类型,但我可以立即看到它们,但我知道这是一个偏好问题。 了解差异有多大的唯一方法是分析。理论上嵌套工作O(n) 和平面是O(e^n) @talex 理论上要么更快,要么速度相同,所以你不应该根据性能来选择。 【参考方案1】:

您应该选择最能表达代码含义的选项,而不用担心性能。如果match 的性能对您的代码至关重要,那么您的设计就会遇到更大的问题。 (也不清楚一个性能优于另一个,因此基于假设性能进行选择是不明智的)。

如果每个case 都会导致一段独立的代码,那么拥有一个扁平的match 是最直接的逻辑表达方式。添加虚假嵌套只会使事情变得混乱。

如果两个或多个case 表达式之间有一些公共代码,则可以将它们分组到嵌套的match 语句中,这样公共代码就不会重复。如果您想在代码中表达的多个案例之间存在某种逻辑共性,这也可能适用。

还请注意,您可以使用 orElse 链接部分函数,​​这允许您将一个大的 match 拆分为具有有意义名称的单独函数,同时避免嵌套 match 语句。

【讨论】:

以上是关于Scala中的嵌套与展平模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

Scala 匹配模式

scala学习笔记-模式匹配(16)

Scala入门到精通——第十五节 Case Class与模式匹配

Scala-Unit5-Scala面对对象与模式匹配

Scala 模式匹配详解

模式匹配范围在Scala与Spark udf