如何在 F# 中定义类型成员常量?

24
在C#中,可以像这样定义类型成员常量:
class Foo { public const int Bar = 600; }

IL的样子是这样的。

.field public static literal int32 Bar = int32(600)

我该如何在Visual F# / FSharp中实现同样的功能?

我尝试了以下代码但并没有成功:

[<Sealed>]
 type Foo() =

    [<Literal>]
    let Bar = 600

1
我问了这个问题 - https://dev59.com/o3I-5IYBdhLWcg3weoPR - Chris Smith指出这是不可能的。 - Daniel
2个回答

23

我对F#编译器进行了一些实验,以下是我的一些观察。如果您想创建IL字面量,则需要将标记为Literal的值放置在模块内。例如:

module Constants = 
  [<Literal>]
  let Num = 1

顺带一提,我快速查阅了F#规范,发现文字字面量在模式匹配中非常有用,因为您可以将它们作为模式使用(只要它们以大写字母开头):

open Constants
match 1 with
| Num -> "1"
| _ -> "other"

现在,问题是为什么当你把Literal放在类型声明内部时,它不像你预期的那样工作。我认为原因是在F#类型声明中,let声明不能是公共的,只能在类/类型内部可见。我相信当你在类型声明中使用C#和F#内联文字值时,这也是可以完成的。但是由于该字面值不能是公共的,因此没有理由生成literal IL字段,因为任何人都无法访问它。


在C#中,字面量将被内联到字节码中,但const字段仍将存在,以供其他类型使用。 - zproxy
是的 - 在 F# 中,如果字面量是公共的(例如在模块中),并且可以被其他人使用,则会生成 field;如果它只在类内部可见,则没有生成字节码的意义,因为其他类型无法使用它。 - Tomas Petricek

2

我不确定这是否可能。实际上,我甚至认为您无法创建不可变的公共字段,更不用说常量了。


我相信使用“val”声明并在构造函数中使用“new()”进行显式初始化,您可以创建公共不可变字段,但这对于常量无效,因为“val”字段在构造函数中初始化。 - Tomas Petricek
@Tomas - 我认为你会发现你的建议实际上会导致定义一个属性,而不是字段。然而,使用 val mutable 确实会导致可变字段。 - kvb
你是对的。public val 会生成一个带有私有字段的属性(这样做的动机是禁止可能使用该类的 C# 用户修改应该是不可变的字段)。 - Tomas Petricek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接