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

use*_*761 10 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 
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 11

我无法解释为什么编译器会在您的特定情况下发出此警告 - 我同意@ildjarn您可以放心地忽略它,因为编译器可能只是过于谨慎.

但是,我可以给你一个例子,警告可能会给你一个有用的提示,说明某些事情可能没有你想象的那样.如果我们有这样的可变struct:

[<Struct>]
type Test =
  val mutable ticks : int64
  member x.Inc() = x.ticks <- x.ticks + 1L
  new (init) = { ticks = init }
Run Code Online (Sandbox Code Playgroud)

现在,该Inc方法改变了struct(你也可以访问mutable字段ticks).我们可以尝试编写一个创建Test值并使其变异的函数:

let foo () =
  let t = Test(1L)
  t.Inc()  // Warning: The value has been copied to ensure the original is not mutated
  t
Run Code Online (Sandbox Code Playgroud)

我们没有将本地值标记tmutable,因此编译器会在我们调用时尝试确保该值不会发生变化Inc.它不知道是否Inc改变了值,所以唯一安全的是创建一个副本 - 从而foo返回值Test(1L).

如果我们标记tmutable,那么编译器不必担心因调用而改变它,因此它不会发出警告(并且函数返回Test(2L)):

let foo () =
  let mutable t = Test(1L)
  t.Inc()
  t
Run Code Online (Sandbox Code Playgroud)

我不确定在你的例子中导致警告的是什么.也许编译器认为(作为一些中间表示的结果)Ticks操作可以改变左侧值(System.DateTime.Nowt分别)并且它想要阻止它.

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

  • “ *因此`foo`返回值'Test(1L)`。*”我发现这种行为令人惊讶-语义上的重大变化与人们期望代码执行的行为不同,所以为什么这是5级在默认值为3时发出警告?一个人可以坐下来调试几个小时,试图解决类似的问题。 (2认同)
  • @ildjarn - 我怀疑理由是这样的:在f#2.0中有警告,所以F#3.0中的默认值也不能发出警告,否则如果人们使用`warnaserror`它会破坏代码.有趣的是,C#具有相同的行为 - 请参阅http://blogs.msdn.com/b/ericlippert/archive/2008/05/14/mutating-readonly-structs.aspx (2认同)