在 Python 中模拟 switch 语句的 fall-through 行为

·

3 min read

什么是 fall-through

在 JavaScript 中,switch 语句允许 fall-through 行为。当在 switch 语句中发现匹配条件时,相应的代码块将被执行,直到遇到 break 语句,此时 switch 语句将退出。如果没有提供 break 语句,程序将继续执行下一个 case,而不管它是否与条件匹配。这就是所谓的 fall-through 行为。

switch (Animal) {
    case "Dog":
    case "Cow":
        console.log("This animal is friend of people.");
    case "Giraffe":
    case "Pig":
        console.log("This animal is not extinct.");
        break;
    case "Dinosaur":
    default:
        console.log("This animal is extinct.");
}

fall-through 何时有用

在多个 cases 共享同一代码块或需要跨多个 cases 执行一连串操作时,switch 语句中的 fall-through 会非常有用。以下是一些例子:

  1. 将多个 cases 组合在一起: 当多个 cases 需要执行相同的代码块时,fall-through 可让您一个接一个地列出这些 cases,而无需重复每个 case 的代码块。这可以使代码更简洁,更易于维护。

      switch (dayOfWeek) {
          case "Saturday":
          case "Sunday":
              console.log("It's the weekend!");
              break;
          default:
              console.log("Looking forward to the Weekend");
      }
    
  2. 不同 cases 下的顺序操作: 在需要执行一系列操作的情况下,如果这些操作是建立在彼此基础之上的,但只是针对不同的情况从序列中的不同点开始执行,那么 fall-through 可以让您在不重复代码的情况下对这些操作进行结构化处理。

      switch (userLevel) {
          case "beginner":
              beginnerTasks();
              // Fall through to execute intermediate tasks as well.
          case "intermediate":
              intermediateTasks();
              // Fall through to execute advanced tasks as well.
          case "advanced":
              advancedTasks();
              break;
      }
    
  3. 设置特定条件下默认值: 您可以使用 fall-through 功能为某些情况设置默认值,然后在后面的特定情况中覆盖这些默认值。

      switch (productType) {
          case "book":
              basePrice = 5;
              break;
          case "video":
          case "software":
              // These types have a base price and additional licensing fee.
              basePrice = 20;
              // Fall through to add licensing fee.
          default:
              licensingFee = 10;
      }
    
  4. 复杂的条件逻辑:当触发一个案例的逻辑比较复杂,涉及多个步骤或条件,并且这些步骤或条件相互依存时,可以使用 fall-through 功能以可读和高效的方式来构建这一逻辑。

      switch (true) {
          case (score >= 90):
              grade = "A";
              break;
          case (score >= 80):
              // Fall through to check for specific conditions within this range.
          case (score >= 70 && extraCredit):
              grade = "B";
              break;
          default:
              grade = "C";
      }
    

这些示例演示了在多个 cases 共享逻辑或需要跨 case 执行一系列操作的情况下,如何利用fall-through 来编写更高效、可读性和可维护性更强的代码。

Python 的模式匹配

Python 3.10 引入了一个名为 match-case 语句的新特性,也称为模式匹配。该特性为处理条件逻辑提供了一种更具表现力的方式,类似于其他语言(如 JavaScript 或 C++)中的 switch 语句。

然而,与 switch 语句不同的是,在 Python 的 match-case 语句中,cases 之间没有 "fall-through"。

下面是一个如何在 Python 中使用 match-case 语句的示例:

status = 404  # replace with the actual status
match status:
    case 400:
        result = "Bad request"
    case 404:
        result = "Not found"
    case 418:
        result = "I'm a teapot"
    case _:
        result = "Unknown status"
print(result)

在这个示例中,match 关键字后面是要匹配的表达式 (status),case 后面是要匹配的模式。最后一个 case 语句中的 _ 是一个通配符,可以匹配任何内容,类似于 switch 语句中的 default case。

您还可以使用更复杂的模式,并在模式中添加 guard 子句。guard 是一个 if 子句,它进一步细化了 case 的条件。如果 guard 为 false,则 match 会继续尝试下一个 case 块。

point = (1, 1)  # replace with the actual point
match point:
    case (x, y) if x == y:
        # the case statement matches a tuple and 
        # uses a guard to check if the two elements of the tuple are equal.
        print(f"The point is located on the diagonal Y=X at {x}.")
    case (x, 0):
        print(f"X={x} and the point is on the x-axis.")
    case (0, y):
        print(f"Y={y} and the point is on the y-axis.")
    case (0, 0):
        print("The point is at the origin.")
    case (x, y) if x > 0 and y > 0:
        print(f"The point is in the first quadrant at ({x}, {y}).")
    case _:
        print(f"Point is not on the diagonal or axes at ({x}, {y}).")

如何在 Python 中模拟 switch 的 fall-through

不使用 fall-through

if user_level == "beginner":
    beginnerTasks()
    intermediateTasks()
    advancedTasks()
elif user_level == "intermediate":
    intermediateTasks()
    advancedTasks()
elif user_level == "advanced":
    advancedTasks()

模拟 fall-through

在 Python 中,您可以使用一系列 if 语句和一个标志变量来模拟 switch 语句的 fall-through 行为。以下代码可供参考:

fall_through = False

if user_level == "beginner":
    beginnerTasks()
    fall_through = True
if fall_through or user_level == "intermediate":
    intermediateTasks()
    fall_through = True
if fall_through or user_level == "advanced":
    advancedTasks()

在这段代码中,fall_through 变量用于控制是否执行后续 if 语句中的代码。如果 user_level 为 "beginner",则调用 beginnerTasks(),并将 fall_through 设为 True。这将导致执行下一个 if 语句中的代码,而不验证 user_level 的值。同样的逻辑也适用于 "intermediate" 级别。如果 user_level 是 "advanced",那么只有 advancedTasks() 被调用,因为 fall_through 在开始时是 False

Python 的 match-case 语句的优点

在支持 fall-through 的语言(如 C 或 JavaScript)中,它的风险在于,如果程序员忘记在每个 case 的结尾加入 break 语句,就可能导致错误。如果没有 break,程序将继续执行下一个 case 的代码,这可能不是预期的行为,会导致意想不到的结果。

Python 3.10 引入的 match-case 语句的优点包括:

  1. 无跳转: Python 的 match-case 没有 fall-through 行为,这消除了意外执行多个 cases 的风险。一旦发现匹配,Python 会执行相应 case 块中的语句,然后跳到 match 块的末尾,继续执行程序的其余部分。

  2. 模式匹配:match-case 语句是为模式匹配而设计的,它比简单的值匹配更强大。它允许匹配类型模式,而不仅仅是值,这可以使代码更具表现力和可读性。

  3. 复杂匹配: Python 的 match-case 可以处理复杂的匹配,并且可以在单个 case 块中处理多种可能的情况,这可以简化逻辑并减少嵌套 if 语句的需要。

  4. 可读性: match-case 语句提供了一种结构清晰的方式来处理多个条件,从而使代码更具可读性,这通常比一长串 if-elif-else 语句更优雅。

  5. 多重模式: 您可以使用 | 操作符在单例中匹配多个模式,从而以简洁的方式处理多个相关条件,而无需重复代码。

  6. 默认情况:match-case 语句中的默认情况用下划线 _ 表示,它可以捕获前面 cases 中没有匹配到的任何值,确保涵盖所有可能性。

总之,Python 的 match-case 语句为传统 fall-through 行为的 switch 语句提供了一个更安全、更强大的替代方案,减少了 bug 的风险,提高了代码的清晰度。