前几天我在F#(+ .NET Core 3.1)中遇到了关于let
绑定初始化(变量)的某些意外情况,这种初始化并不总是根据程序编译器的配置而发生:调试或发布。
好吧,问题沿着这些思路发展了(我故意简化了代码,并且行为仍然可以重现),我创建了一个项目,它是一个带有单个文件的控制台,如下:
Program.fs
:
open System
open ClassLibrary1
open Flurl.Http
[<RequireQualifiedAccess>]
module Console =
let private init =
printfn "Console: A"
FlurlHttp.Configure(fun settings ->
printfn "Console: B"
settings.AfterCall <- Unchecked.defaultof<Action<FlurlCall>>)
let doStuff () =
init
printfn "Console: C"
[<EntryPoint>]
let main _ =
Console.doStuff()
Library.doStuff()
0
ClassLibrary1
命名空间实际上是引用到控制台项目的库项目。
该库项目也由单个文件组成:
Library.fs
:
namespace ClassLibrary1
open System
open Flurl.Http
[<RequireQualifiedAccess>]
module Library =
let private init =
printfn "Library: A"
FlurlHttp.Configure(fun settings ->
printfn "Library: B"
settings.AfterCall <- Unchecked.defaultof<Action<FlurlCall>>)
let doStuff () =
init
printfn "Library: C"
运行控制台项目时的区别
发布输出:
Console: A
Console: B
Console: C
Library: C
调试输出:
Console: A
Console: B
Console: C
Library: A
Library: B
Library: C
[这有点令人不安,我和我的同事花了很多时间试图找出正在发生的事情。
所以我只想在这种情况下确认编译器优化规则。
我对atm的理解是:
我想知道我的理解是否正确。
[编辑]
[本特·特兰伯格(Bent Tranberg)建议我的帖子抄袭为:Module values in F# don't get initialized. Why?
所以我检查了该帖子中给出的答案:
Brian将我指向this part of the spec,这表明这是预期的行为。
似乎一种解决方法是提供一个明确的入口点,如下所示:
[<EntryPoint>] let main _ = 0
所以我确实在库项目中添加了一个入口点
Library.fs
module ClassLibrary1
open System
open Flurl.Http
[<RequireQualifiedAccess>]
module Library =
let private init =
printfn "Library: A"
FlurlHttp.Configure(fun settings ->
printfn "Library: B"
settings.AfterCall <- Unchecked.defaultof<Action<FlurlCall>>)
let doStuff () =
init
printfn "Library: C"
[<EntryPoint>]
let callMe _ =
Library.doStuff ()
0
并如下更改可执行程序:
open System
open ClassLibrary1
open Flurl.Http
[<RequireQualifiedAccess>]
module Console =
let private init =
printfn "Console: A"
FlurlHttp.Configure(fun settings ->
printfn "Console: B"
settings.AfterCall <- Unchecked.defaultof<Action<FlurlCall>>)
let doStuff () =
init
printfn "Console: C"
[<EntryPoint>]
let main _ =
Console.doStuff()
callMe [||] |> ignore
0
和以前一样,发生了同样的事情。
我什至将Library项目类型更改为可执行项目,也没有任何改变...
[这需要一些挖掘。这是两个不同问题的结果: