为什么字面量默认情况下不是常量?

6
如果F#鼓励编写不可变的急切评估数据,为什么F#没有默认强制简单的let绑定为const
我需要明确地编写[<Literal>]属性。例如:
module ConstVsStaticReadOnly =

    [<Literal>]
    let ConstInt32 = 1

    [<Literal>]
    let ConstString = "A" + "B" + "C"

    let staticReadOnlyBoolean = true

1
“简单绑定”(与其他绑定一样)的值被编译为静态属性。 如果将其中一些静默地变成属性,而另一些则是常量,会引入不一致性,使代码的自动处理(例如分析器、转换器等)更加困难。 - Fyodor Soikin
4
我觉得写let [<Literal>] A = 1更方便,这样还有助于防止代码漂移。 - Bent Tranberg
@FyodorSoikin,你能告诉我为什么处理“const”更难吗?例如,我正在使用Resharper,它使用自己的分析器而不是.NET Roslyn,如果一个“static readonly”可以重构为“const”,它会提醒我。 - MiP
处理常量并不比处理属性更难。处理两者都比处理任何一个更难。 - Fyodor Soikin
1个回答

9
当在.NET中使用const时,所有对它的引用在编译时会被替换为其值。这听起来很好,但当你意识到它不仅限于定义常量的程序集时,就会发现问题所在。引用它的其他程序集也会在编译时复制常量的值。您可以在一个简单的示例中看到结果:创建一个新的F#库项目和一个单一模块。
module ConstTest 

let [<Literal>] ConstInt = 1
let NotConstInt = ConstInt

接下来是一个引用了该库的控制台应用程序

[<EntryPoint>]
let main argv = 
    printfn "%A %A" ConstTest.ConstInt ConstTest.NotConstInt
    0

运行时,它打印出 1 1 - 如预期。

现在修改库中的常量。

module ConstTest 

let [<Literal>] ConstInt = 2
let NotConstInt = ConstInt

构建库(但不是控制台应用程序!),将dll复制到控制台应用程序文件夹并运行应用程序。它会打印出1 2。如果您不知道这种行为,那么会很惊讶。
一旦创建了公共常量,它就永远不应该更改。这就是编译器不会隐式创建常量的原因。

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