已复制f#:value生成的警告,以确保原始文件未发生变异

时间:2012-12-06 21:54:45

标签: f#

当使用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 

1 个答案:

答案 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 操作可以改变左侧值(分别为TicksSystem.DateTime.Now)并且它想要防止这种情况。

奇怪的是,如果你在F#中编写自己的t结构,除非你将变量DateTime标记为t,否则会在两种情况下都收到警告(这就是我'期待',但标准mutable的行为是不同的。所以也许编译器知道我遗漏的标准类型...