在The F# 4.0 Language Specification中,它说:
7.2命名模式
如果 long-ident 超过一个字符长或以大写字符开头(即,如果 System.Char.IsUpperInvariant true 且 System.Char.IsLowerInvariant 在第一个字符上 false ),使用模式中的名称解析来解析它(§14.1.6)。该算法产生以下之一:
- 工会案例
- 异常标签
- 活动模式案例名称
- 字面值
所以下面的代码不起作用:
[<Literal>]
let zero = 0
let matchZero = function
| zero -> printfn "Is %A" zero
| _ -> printfn "Not 0"
zero
应与模块一起使用,或者首字母大写为Z
:
module Match =
[<Literal>]
let zero = 0
let matchZero = function
| Match.zero -> printfn "Is %A" Match.zero
| _ -> printfn "Not 0"
///////////////////////////////////////
///////////////////////////////////////
[<Literal>]
let Zero = 0
let matchZero = function
| Zero -> printfn "%A" Zero
| _ -> printfn "Not 0"
为什么文字zero
必须使第一个大写字母正常工作?
答案 0 :(得分:3)
这就是语言的设计方式。没有必要问&#34;为什么&#34;,除了编译器说必须这样做之外没有任何根本原因。
决定背后的基本原理可能如下:当匹配模式时,编译器需要以某种方式确定您是否尝试匹配特定值或匹配任何值并将其绑定到名称。请考虑以下事项:
match 1 with
| zero -> printfn "Zero!"
| x -> printfn "Got a value: %d" x
在此背景下x
和zero
之间的主要区别是什么?对于编译器,它们看起来完全一样。因此,当编译器需要决定是生成if 1 = zero then printfn "Zero!"
之类的代码还是生成像let x = 1; printfn "Got a value: %d" x
之类的代码时,做出此决定的依据是什么?如何从x
案例中告诉zero
案例?
所以,发明了一个人为的基础:如果模式是大写的,那么它是zero
- case,如果它以小写字符开头,那么它就是x
- 情况
注意:当文字在模块中时,根本不会出现这种模糊,因为只有一种方法可以解释包含点的模式。
问:但是,编译器无法查看上面是否实际定义了zero
,然后根据它做出决定?
A:嗯,是的,它可以(事实上,这正是它的作用,这就是为什么你得到编译时警告),但是会导致不可预见的后果:当你第一次写匹配时,你定义了zero
,而match
表达式只会匹配零。但是稍后在你的程序演变中,某人决定因某种原因删除zero
,现在match
表达式将匹配任何内容,并且不会产生任何编译时错误!你会有一个微妙的错误,它不会被编译器捕获,所以你唯一的希望是你的单元测试或QA人员。防止这种事情的发生非常值得强制命名实践的轻微不便。