[<Literal>]与F#中的其他常量有何不同?

Mic*_*ahl 27 f#

我对Literal关键字有点困惑,为什么在F#中有必要.

阅读文档,听起来我[<Literal>]用它来定义一个常量,但是我有点困惑这个常量如何与F#中的所有其他常量不同.

可以使用Literal属性标记要作为常量的值.此属性具有将值编译为常量的效果.

当我想到一个常数时,我会想到一些不可改变的东西......

let x = "a" + "b" //this is a immutable value, its value is constant
[<Literal>]
let y = "a" + "b" //this is also a immutable value, but why is this a special constant?
Run Code Online (Sandbox Code Playgroud)

是因为"普通"F#值被懒惰地评估而且[<Literal>]不会被懒惰地评估.?他们的意思是'编译为常数'..?或者还有别的东西吗?

Joh*_*lds 39

在您的示例中,x是一个在运行时分配的不可变值(但不是懒惰地评估),而是y在编译期间分配的.举个例子,

let myDLL = "foo.dll"

[<DllImport(myDLL, CallingConvention = CallingConvention.Cdecl)>]
extern void HelloWorld()
Run Code Online (Sandbox Code Playgroud)

不起作用,因为DllImport是一个属性,需要知道myDLL编译期间的值.但是,这将有效:

[<Literal>]
let myDLL = "foo.dll"

[<DllImport(myDLL, CallingConvention = CallingConvention.Cdecl)>]
extern void HelloWorld()
Run Code Online (Sandbox Code Playgroud)

  • 您可能还需要注意.NET互操作的重要性.装饰的字段`[<Literal>]`被编译为IL作为常量,这对代码的使用者有一定的影响.例如,请参阅http://stackoverflow.com/a/755693/385844. (3认同)
  • 请注意,根据 f# 命名约定,文字应为 PascalCase。如果您将它们用于模式匹配,这不仅仅是约定:https://docs.microsoft.com/sv-se/dotnet/fsharp/language-reference/literals (2认同)

cyn*_*nic 19

如果您来自C#background,您可以将Literal值视为const字段,将非文字视为readonly字段.同样的差异也适用.


Joh*_*mer 11

我认为更好的例子是a match.

这不符合您的期望:

let t = 3
match q with
|t -> printfn "this always happens"
|_ -> printfn "this never happens" //and produces a compiler warning
Run Code Online (Sandbox Code Playgroud)

另一方面:

[<Literal>]
let t = 3
match q with
|t -> printfn "q is 3"
|_ -> printfn "q isn't 3"
Run Code Online (Sandbox Code Playgroud)

因此,这Literal是一个编译时常量,我们可以将它用于模式匹配.

  • 不幸的是,这个例子区分大小写.要按照描述工作,文字标识符`t`必须以大写字母开头.对非文字版本使用大写会产生额外的编译器警告,但功能相同. (3认同)