积极的F#编译器优化是否仅在引用的依赖项+版本配置上发生?

问题描述 投票:3回答:1

前几天我在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项目类型更改为可执行项目,也没有任何改变...

.net-core f# compiler-optimization
1个回答
0
投票

[这需要一些挖掘。这是两个不同问题的结果:

© www.soinside.com 2019 - 2024. All rights reserved.