F#中是否可以直接模式匹配let绑定?
例如,编译时没有任何警告:
let value =
match arg with
| 1 -> "value1"
| 2 -> "value2"
| _ -> failwith "key not found"
以下内容提供了警告"此规则永远不会与匹配key2
和_
的行匹配" :
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
这是因为虽然它们是不可变的,但let绑定与C#const
变量不同吗?
答案 0 :(得分:6)
只需使用大写字母和[<Literal>]
它们就可以正常工作。
let [<Literal>] X = 0
let [<Literal>] Y = 1
let bla arg =
match arg with
| X -> "zero"
| Y -> "one"
| somethingelse -> somethingelse.ToString()
按惯例,小写名称通常表示绑定到名称的通配符。
答案 1 :(得分:5)
您收到该错误的原因是因为在匹配表达式的pattern子句中使用变量名时F#正在执行的操作。
假设我有
match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"
我认为这是关键,尽管在匹配之前没有定义x或y,但这段代码仍然有用。这是因为x和y只是短代码,这使得编写匹配表达式更容易。在幕后,F#编译器实际上将x when x = 0
转换为“let binding”,其中x
绑定到arg
。然后可以在x
表达式和x = 0
之后的表达式中使用->
。
回到你遇到的问题:
let key1 = 1
let key2 = 2
let value =
match arg with
| key1 -> "value1"
| key2 -> "value2"
| _ -> failwith "key not found"
这不起作用的原因是因为在匹配表达式中,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"
(为什么是的,F#会让你把绑定扔进if表达式中)
此if / else表达式等同于您的匹配表达式。在这种形式中,很明显第一个条件总是评估为真。
我不会把它放在这里,但它可能有助于查看匹配表达式的代码引用。在我看到他们生成的抽象语法树看起来像什么之前,我并没有真正了解匹配表达式的内容。
答案 2 :(得分:2)
如果要在模式匹配的情况下匹配特定值,则只能使用文字。标识符表示绑定 - 即此模式匹配案例中的实际值将绑定到在本案范围内可见的标识符。
正如@DanielFabian所示,您可以定义自己的文字并为其命名。
如果你需要匹配的值在编译时是不知道的,你可以使用这样的守卫:
match arg with
| x when x = key1 -> "value1"
| x when x = key2 -> "value2"
| _ -> // etc
有关详细信息,请参阅MSDN article on pattern matching。
答案 3 :(得分:1)
您尝试使用的代码引发了两个主要问题。
首先是模式匹配:
match arg with
| _ -> "value"
将arg与任何内容匹配,然后返回&#34;值&#34;
match arg with
| a -> "value"
将arg与任何内容匹配,调用它&#34; a&#34;,然后返回&#34;值&#34;。您可以将匹配视为拥有自己的小命名空间,a只存在于匹配中,而且只有匹配才能看到&#39;已经在其中命名的东西。
其次,如果要匹配一组预定义值,那么您可能希望使用有区别的联合。你可以这样定义一个:
type Keys=
| Key1
| Key2
然后像这样匹配:
match arg with
| Key1 -> "value1"
| Key2 -> "value2"
在这种情况下,它匹配Keys类型,而不是名为Key1或Key2的值。