首页 > 解决方案 > let vs member in F#,需要澄清一些事情

问题描述

让我们考虑以下代码:

type RulesStore() =

    ...
    static member LoadAsync : Async<RulesStore> =
        async {
            let! r = Startup.States.GetAsStringAsync("rules") |> Async.AwaitTask

            return
                if String.IsNullOrEmpty r then
                    new RulesStore()
                else
                    JsonConvert.DeserializeObject<RulesStore>(r);
        }

这是对象内部的静态方法,用于从存储的 json 或新的干净的 json 中获取该对象的实例。

我是否正确地相信,如果我更换:

静态成员 LoadAsync : Async =

让 LoadAsync : 异步 =

LoadAsync 将被评估一次,随后的加载将返回相同的结果?如果我错了,这是为什么呢?

标签: f#

解决方案


这有点微妙。首先,您将let(instance) 与static member(static) 进行比较,这增加了每个实例发生的事情与所有实例共享的事情之间的明显区别。

更有用的比较是比较正则memberlet. 微妙的是async计算本身是延迟的,所以它们只在你执行它们时才运行。

以下是一个示例来说明这一点 - 我在块printf的定义之前添加了一个async和一个async,用于两个letmember

type A() = 
  let test = 
    printfn "let: before async"
    async { 
      printfn "let: inside async"
    }
  member x.Test =
    printfn "member: before async"
    async { 
      printfn "member: inside async"
    }
  member x.RunLet() = test |> Async.RunSynchronously
  member x.RunMember() = x.Test |> Async.RunSynchronously

以下是代码的作用:

let a = A() 
// prints "let: before async"
a.RunLet()  
// prints "let: inside async"
a.RunLet()  
// prints "let: inside async"
a.RunMember()  
// prints "member: before async"
// and "member: inside async"
a.RunMember()  
// prints "member: before async"
// and "member: inside async"

如您所见,每次调用异步计算时,“异步内部”的代码都会重复运行。但是,“异步之前”的代码只运行一次 forlet并且重复 for member

实际上,在异步之前您几乎没有代码,因此这在典型用途中没有太大区别,但有一些区别 - 使用let,异步计算只构建一次,然后每次重用。


推荐阅读