如何构造匹配表达式

oct*_*bus 2 f# command-line parsing pattern-matching

我允许像这样的命令行参数--10GB,其中--GB是常量,但是可以在常量值之间替换像 1、10 或 100 这样的数字,例如--5GB

我可以轻松解析字符串的开头和结尾substr,但想使用match它。我只是不确定如何构造匹配表达式。

let GB1     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1))
let arg = argv.[0]

let match_head = "--"
let match_tail  = "GB"

let parse_min_gb_arg arg =
    match arg with
    | match_head & match_tail -> cvt_gb_arg_to_int arg
    | _ -> volLib.GB1
Run Code Online (Sandbox Code Playgroud)

我收到一条警告,提示_ This rule will never be matched.“如何构建 AND 表达式?”

Fyo*_*kin 5

除了匹配整个值之外,您不能匹配字符串,例如match s with | "1" -> 1 | "2" -> 2 ...

解析开头和结尾将是最有效的方法,无需变得聪明(顺便说一句,这是一个普遍正确的陈述)。

但如果你真的想使用模式匹配,那绝对是可以做到的,但是您必须为自己制作一些自定义匹配器(也称为“活动模式”)。

首先,创建一个自定义匹配器,它将解析出由前缀和后缀包围的字符串的“中间”部分:

let (|StrBetween|_|) starts ends (str: string) =
  if str.StartsWith starts && str.EndsWith ends then 
    Some (str.Substring(starts.Length, str.Length - ends.Length - starts.Length))
  else 
    None
Run Code Online (Sandbox Code Playgroud)

用法:

let x = match "abcd" with 
        | StrBetween "a" "d" s -> s
        | _ -> "nope"
// x = "bc"
Run Code Online (Sandbox Code Playgroud)

然后创建一个自定义匹配器来解析一个整数:

let (|Int|_|) (s: string) = 
    match System.Int32.TryParse s with 
    | true, i -> Some i 
    | _ -> None
Run Code Online (Sandbox Code Playgroud)

用法:

let x = match "15" with 
        | Int i -> i
        | _ -> 0
// x = 15
Run Code Online (Sandbox Code Playgroud)

现在,将两者结合起来:

let x = match "--10GB" with 
        | StrBetween "--" "GB" (Int i) -> i 
        | _ -> volLib.GB1
// x = 10
Run Code Online (Sandbox Code Playgroud)

模式的这种组合和嵌套的能力是它们的主要功能:您可以用易于理解的小片段构建复杂的模式,并让编译器将其与输入相匹配。这基本上就是为什么它被称为“模式匹配”。:-)

  • 没有人考虑过字符串切片语法。`一些 str.[starts.Length .. str.Length -ends.Length - 1]` (2认同)