繁体   English   中英

使用 scala 模式匹配而不是 java switch case 有什么优势?

[英]What is the advantage of using scala pattern matching instead of java switch case?

每个人都说模式匹配是函数式语言的一大特色。 为什么?

我不能简单地使用 ifs 和 switch cases 来处理所有事情吗?

我想了解使用模式匹配而不是常规过程编程 ifs 和 switch cases 的优势

我首先要指出的是,您不使用模式匹配“代替”switch 语句。 Scala 没有switch语句,它有的是匹配块,里面的 case 表面上看起来非常类似于 switch 语句。

使用模式匹配匹配块可以完成switch所做的一切,等等。

A) 它不仅限于原语和 Oracle 在语言规范(字符串和枚举)中选择“祝福”的其他类型 如果您想匹配自己的类型,请继续!

B) 模式匹配也可以提取. 例如,对于一个元组:

val tup = ("hello world", 42)
tup match {
  case (s,i) =>
    println("the string was " + s)
    println("the number was " + i
}

附上清单:

val xs = List(1,2,3,4,5,6)
xs match {
  case h :: t =>
    // h is the head: 1
    // t is the tail: 2,3,4,5,6
    // The :: above is also an example of matching with an INFIX TYPE
}

带案例类

case class Person(name: String, age: Int)
val p = Person("John Doe", 42)
p match {
  case Person(name, 42) =>
    //only extracting the name here, the match would fail if the age wasn't 42
    println(name)
}

C) 模式匹配可用于赋值和 for-comprehensions ,而不仅仅是在匹配块中:

val tup = (19,73)

val (a,b) = tup

for((a,b) <- Some(tup)) yield a+b // Some(92)

D) 匹配块是表达式,而不是语句

这意味着它们对匹配的任何案例的主体进行评估,而不是完全通过副作用起作用。 这对于函数式编程至关重要!

val result = tup match { case (a,b) => a + b }

不知何故,我对@KevinWright 答案的编辑/添加被丢弃了,所以我将在此处添加它作为另一个不错的模式匹配功能......

F) 编译器详尽检查案例。

如果存在现有案例未涵盖的值匹配,编译器将警告您。 这是该语言的一个非常好的特性,因为如果您不忽略这些编译器警告,您将不会捕获此类运行时异常或遇到您没有想到的情况。 如果您仍然运行应用程序并忽略警告,如果您的值与任何情况都不匹配,您将获得一个很好的描述性异常。 这是一个插图:

scala> def badMatch(l: List[Int]): Unit = l match { case x :: xs => println(x) }
<console>:7: warning: match may not be exhaustive.
It would fail on the following input: Nil
       def badMatch(l: List[Int]): Unit = l match { case x :: xs => println(x) }
                                          ^
badMatch: (l: List[Int])Unit

scala> badMatch(List(1, 2))
1

scala> badMatch(Nil)
scala.MatchError: List() (of class scala.collection.immutable.Nil$)

在这种情况下,我更喜欢得到一个异常,因为它会大声而清晰地失败,而且通常很早,而不是执行意外的逻辑分支。

如果您使用if必须使用else ,并且如果您使用 Java switch ,则您必须使用default case 来涵盖所有情况。 但请注意不同之处:Scala 编译器知道在这种情况下您的空列表与非空列表不同,或者更广泛地说,您定义了匹配的粒度。 您可以将列表与 1 或 2 个元素匹配并忽略其余元素,或者使用任何其他更复杂的模式,而不必担心是否设法涵盖所有​​情况。

总之,当您使用复杂的提取和匹配逻辑时,编译器将确保您不会遗漏任何情况。 Java 中没有类似的东西,除非您使用defaultelsedefault

模式匹配在某种程度上不是switch 语句的替代方案,我认为它是在 oop 中进行动态调度的另一种方式。 他们尝试做同样的事情:根据参数的动态类型调用不同版本的函数

正如在其他答案中所写的那样,Scala 模式匹配和 Java 开关不会做同样的事情。

开关语句:

  • 仅适用于本机类型、枚举类型和 String 类
  • 根据命令式编程,它是创建多个执行路径的“if-else”链的替代方案

模式匹配:

  • 它允许使用首次匹配策略匹配任何类型的数据
  • 它满足一个函数逻辑:每个case语句返回一个值,整个match语句实际上是一个返回匹配case值的函数。

换句话说,您可以将“模式匹配”用于与“java 开关”类似的目的,但这样做是以命令式方式使用功能性工具。

JMPL是一个简单的 java 库,它可以使用 Java 8 的特性来模拟一些特性模式匹配。

      matches(data).as(
          new Person("man"),    () ->  System.out.println("man");
          new Person("woman"),  () ->  System.out.println("woman");
          new Person("child"),  () ->  System.out.println("child");        
          Null.class,           () ->  System.out.println("Null value "),
          Else.class,           () ->  System.out.println("Default value: " + data)
       );


       matches(data).as(
          Integer.class, i  -> { System.out.println(i * i); },
          Byte.class,    b  -> { System.out.println(b * b); },
          Long.class,    l  -> { System.out.println(l * l); },
          String.class,  s  -> { System.out.println(s * s); },
          Null.class,    () -> { System.out.println("Null value "); },
          Else.class,    () -> { System.out.println("Default value: " + data); }
       );

       matches(figure).as(
          Rectangle.class, (int w, int h) -> System.out.println("square: " + (w * h)),
          Circle.class,    (int r)        -> System.out.println("square: " + (2 * Math.PI * r)),
          Else.class,      ()             -> System.out.println("Default square: " + 0)
       );

摘自 Martin Odersky(Scala 的创建者)和其他人在 Scala 中编写的一本很棒的书 Programming

Java的switch

  • 可以case整数类型、枚举和常量
  • 在每个备选方案的末尾break
  • 从一种选择跌落到另一种选择而没有break
  • 不会产生值

Scala的match

  • 任何种类的常量,以及其他东西,都可以用于case
  • 每个备选方案结束时没有break
  • 不会从一种选择失败到另一种选择
  • 产生一个值

Java和 Scala 中编程的相同逻辑示例:

Scala

firstArg match
  case "salt" => println("pepper")
  case "chips" => println("salsa")
  case "eggs" => println("bacon")
  case _ => println("huh?")

Java

switch (firstArg) {
  case "salt":
    System.out.println("pepper");
    break;
  case "chips":
    System.out.println("salsa");
    break;
  case "eggs":
    System.out.println("bacon");
    break;
  default:
    System.out.println("huh?");
}

Scala 的match可以产生一个 value ,Java 的switch不能:

friend match
  case "salt" => "pepper"
  case "chips" => "salsa"
  case "eggs" => "bacona"
  case _ => "huh?"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM