当使用f#3.0编译并且警告级别设置为5时,下面的第一个定义会在标题中生成警告。第二个定义干净地编译。我想知道是否有人可以解释编译器担心我可能会意外改变的内容,或者如何使用let子句分割表达式有助于避免这种情况。非常感谢。
let ticks_with_warning () : int64 =
System.DateTime.Now.Ticks
let ticks_clean () : int64 =
let t = System.DateTime.Now
t.Ticks
答案 0 :(得分:11)
我无法解释为什么编译器会在您的特定情况下发出此警告 - 我同意@ildjarn您可以放心地忽略它,因为编译器可能只是过于谨慎。
但是,我可以举一个例子,警告可能会给你一个有用的提示,说明某些事情可能没有你想象的那样。如果我们有这样的可变struct
:
[<Struct>]
type Test =
val mutable ticks : int64
member x.Inc() = x.ticks <- x.ticks + 1L
new (init) = { ticks = init }
现在,Inc
方法会改变结构(您还可以访问可变字段ticks
)。我们可以尝试编写一个创建Test
值并将其变异的函数:
let foo () =
let t = Test(1L)
t.Inc() // Warning: The value has been copied to ensure the original is not mutated
t
我们没有将本地值t
标记为mutable
,因此编译器会在调用Inc
时尝试确保该值不会发生变异。它不知道Inc
是否会改变该值,因此唯一安全的是创建副本 - 因此foo
返回值Test(1L)
。
如果我们将t
标记为mutable
,那么编译器不必担心因调用而改变它,因此它不会发出警告(并且函数返回{{ 1}}):
Test(2L)
我不确定在你的例子中导致警告的是什么。也许编译器认为(作为一些中间表示的结果)let foo () =
let mutable t = Test(1L)
t.Inc()
t
操作可以改变左侧值(分别为Ticks
和System.DateTime.Now
)并且它想要防止这种情况。
奇怪的是,如果你在F#中编写自己的t
结构,除非你将变量DateTime
标记为t
,否则会在两种情况下都收到警告(这就是我'期待',但标准mutable
的行为是不同的。所以也许编译器知道我遗漏的标准类型...