Nic*_*ckL 3 f# immutability pattern-matching guard-clause
在F#中是否可以直接对let绑定进行模式匹配?
例如,这编译时没有任何警告:
let value =
match arg with
| 1 -> "value1"
| 2 -> "value2"
| _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)
以下内容提供警告"此规则将永远不会匹配"与匹配的行key2和_:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)
这是因为虽然它们是不可变的,但是let绑定与C#const变量不同吗?
只需使用大写字母和[<Literal>]它们,它按预期工作.
let [<Literal>] X = 0
let [<Literal>] Y = 1
let bla arg =
match arg with
| X -> "zero"
| Y -> "one"
| somethingelse -> somethingelse.ToString()
Run Code Online (Sandbox Code Playgroud)
按约定,小写名称通常表示绑定到名称的通配符.
您获得该错误的原因是因为在匹配表达式的pattern子句中使用变量名时F#正在执行的操作.
让我说我有
match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"
Run Code Online (Sandbox Code Playgroud)
我认为这是关键,尽管在匹配之前没有定义x或y,但这段代码仍然有效.这是因为x和y只是短代码,这使得编写匹配表达式更容易.在幕后,F#编译器实际上将其x when x = 0转换x为绑定的"let binding" arg. x然后可以在x = 0表达式和表达式之后使用->.
回到你遇到的问题:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)
这不起作用的原因是因为在match表达式中,F#重新绑定key1到值arg,所以key1 -> "value1" is equivalent to如果arg1 = arg1则为"value1".第一个模式将始终匹配; 所以,key2和_永远不会到达.
我不确定我的解释有多清楚,所以我还会提出第二种方法来解释发生了什么:
如果你将匹配表达式转换为if-else,它将如下所示:
let key1 = 1
let key2 = 2
let value =
if let key1 = arg in arg = key1 then
"value1"
else if let key2 = arg in arg = key2 then
"value2"
else
failwith "key not found"
Run Code Online (Sandbox Code Playgroud)
(为什么是的,F#会让你把绑定扔进if表达式)
这个if/else表达式等同于你的匹配表达式.在这种形式中,很明显第一个条件总是评估为真.
我不会把它放在这里,但它可能有助于查看匹配表达式的代码引用.在我看到他们生成的抽象语法树看起来像什么之前,我并没有真正了解匹配表达式的内容.