Case 语句

Example:

  1. let line = readline(stdin)
  2. case line
  3. of "delete-everything", "restart-computer":
  4. echo "permission denied"
  5. of "go-for-a-walk": echo "please yourself"
  6. elif line.len == 0: echo "empty" # optional, must come after `of` branches
  7. else: echo "unknown command" # ditto
  8. # 允许分支缩进;
  9. # 在选择表达式之后的冒号是可选:
  10. case readline(stdin):
  11. of "delete-everything", "restart-computer":
  12. echo "permission denied"
  13. of "go-for-a-walk": echo "please yourself"
  14. else: echo "unknown command"

case 语句类似于 if 语句, 它表示一种多分支选择。 关键字 case 后面的表达式进行求值, 如果其值在 slicelist 列表中, 则执行 of 关键字之后相应语句。 如果其值不在已给定的 slicelist 中, 那么所执行的 elif 、 else 语句部分与 if 语句相同, elif 的处理就像 else: if 。 如果没有 else 或 elif 部分,并且 expr 未能持有所有可能的值,则在 slicelist 会发生静态错误。 但这仅适用于序数类型的表达式。 expr 的 “所有可能的值” 由 expr 的类型决定,为了防止静态错误应该使用 else: discard。

在 case 语句中,只允许使用序数类型、浮点数、字符串和 cstring 作为值。

对于非序数类型, 不可能列出每个可能的值,所以总是需要 else 部分。 此规则 string 类型是例外,目前,它不需要在后面添加 else 或 elif 分支, 但在未来版本中不确定。

因为在语义分析期间检查 case 语句的穷尽性,所以每个 of 分支中的值必须是常量表达式。 此限制可以让编译器生成更高性能的代码。

一种特殊的语义扩展是, case 语句 of 分支中的表达式可以为集合或数组构造器, 然后将集合或数组扩展为其元素的列表:

  1. const
  2. SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
  3. proc classify(s: string) =
  4. case s[0]
  5. of SymChars, '_': echo "an identifier"
  6. of '0'..'9': echo "a number"
  7. else: echo "other"
  8. # 等价于:
  9. proc classify(s: string) =
  10. case s[0]
  11. of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': echo "an identifier"
  12. of '0'..'9': echo "a number"
  13. else: echo "other"

case 语句不会产生左值, 所以下面的示例无效:

  1. type
  2. Foo = ref object
  3. x: seq[string]
  4. proc get_x(x: Foo): var seq[string] =
  5. # 无效
  6. case true
  7. of true:
  8. x.x
  9. else:
  10. x.x
  11. var foo = Foo(x: @[])
  12. foo.get_x().add("asd")

这可以通过显式使用 result 或 return 来修复:

  1. proc get_x(x: Foo): var seq[string] =
  2. case true
  3. of true:
  4. result = x.x
  5. else:
  6. result = x.x