【问题标题】:let vs member for private functions, in F#let vs member 用于私有函数,在 F#
【发布时间】:2019-11-24 22:10:31
【问题描述】:

让我们考虑一下这段代码:

type TransactionTypes =
| TransactionType1
| TransactionType2

type Test() =

    let mutable lastTransactionType1 = DateTime.MinValue
    let mutable lastTransactionType2 = DateTime.MinValue

    let getLastTransaction transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1
        | TransactionType2 -> lastTransactionType2

    let updateLastTransaction transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1 <- DateTime.UtcNow
        | TransactionType2 -> lastTransactionType2 <- DateTime.UtcNow

现在(了解到我仍在学习 F#),我想澄清几点:

类似:

let a = DateTime.Now

进行永久绑定,因此 'a' 在后续使用中总是相同的时间。

但是,我的理解是,如果有参数的话,比如:

let a anyParameter = DateTime.Now

由于参数的存在,每次都会重新评估。对吗?

在上面的代码中,两个 let 语句(getLastTransaction 和 updateLastTransaction)是类型私有的(Test)

我也可以将它们实现为:

member private this.getLastTransaction = ...
member private this.updateLastTransaction = ...

有什么理由让私有函数更喜欢 let vs. member private this? “让可变”已经暗示了这个。所以这两种形式都可以访问这些字段。

那么,一种形式相对于另一种形式的优势是什么?

【问题讨论】:

  • 它将如何回答一种形式与另一种形式的优势?我问这些问题的原因是因为在 let、member 和 val 之间,到字段/方法/属性的映射有点模糊,为什么已经讨论过这个主题,我找不到我写的问题的答案
  • 我可以写 let x _ = 做某事,或成员 this.x = 做某事,或成员 this.x() = 做某事......在实践中必须有一些差异。我想我总是可以将方法实现为属性,所以成员 this.x = 可能不是最好的,但这留下了我的问题:在私人情况下成员 this 与 let .. 真正的区别是什么

标签: f#


【解决方案1】:

当您使用成员时,F# 从 .NET 对象模型中继承了很多东西。一个 .NET 对象可以有几个不同的东西:

  • 字段 - 存储值(就像记录的字段一样)。它们可以是可变的或不可变的。
  • 方法 - 可以使用零个或多个参数调用的方法(如函数)
  • 属性 - 没有参数(如字段);它们可以被读取或写入,但是当发生这种情况时,会调用一些代码。属性基本上是一对 getter 和 setter 方法。

在 F# 中,其中一些不太明显。但是,let 对应于一个字段,而带有参数的member 对应于一个方法。您的棘手案例是没有参数的成员。例如:

type A() = 
  member x.Foo = printfn "Hi"; 42

Hi 将只打印一次,还是每次访问Foo 时都会打印?要回答这个问题,知道Foo 是一个带有getter 的属性是很有用的。以上其实是完整版的语法糖:

type A() = 
  member x.Foo 
    with get() = printfn "Hi"; 42

现在您可以看到Foo 属性后面有一个方法!每次访问Foo,编译器都会生成对get()方法的调用,所以Hi会被重复打印。

【讨论】:

  • so: let=field, member x.Foo 带或不带参数 = 方法或属性?对?但是 let Foo x = 呢?在这种情况下,它也是一种方法,而不是字段
  • let Foo x = ... 是一个 F# 函数,将被编译为方法
  • 那么, let foo x = ... 和 member private this.foo x = ... 之间有什么实际区别吗?出于任何原因,还有一个推荐吗?
  • @Thomas 两者之间几乎没有实际区别 - 如果您使用成员,则可以访问 this 实例(let 不能访问该实例)。这使得let 更容易编译(编译器不需要做一些它会为成员做的检查)。但除此之外,它们是相同的。我更喜欢使用let,因为它更轻量级。
【解决方案2】:

除了托马斯的回答:

  let mutable lastTransactionType1 = DateTime.MinValue

在 C# 中等同于:

internal DateTime lastTransactionType1 = DateTime.MinValue;

member private this.getLastTransaction ...

就 IL 而言,与 IL 相同

let getLastTransaction ...

在等效的 C# 中,两者都是

internal DateTime getLastTransactionMember(TransactionTypes transaction)
{
    if (transaction.Tag != 1)
    {
        return lastTransactionType1;
    }
    return lastTransactionType2;
}

但要以惯用的方式使用 F#,您可能希望使用 let。 还有一点不同,member 确实允许您在声明之前使用绑定中的方法,这在某些情况下可能有用(阅读:hacks)

let getType1 = this.getLastTransactionMember TransactionType1 //this compiles

member private this.getLastTransactionMember transaction =
        match transaction with
        | TransactionType1 -> lastTransactionType1
        | TransactionType2 -> lastTransactionType2

【讨论】:

  • 这带来了一个额外的问题:让 foo x = ... 被评估一切,让 foo = 3 不是,但是你让 foo = doSomethingThatDoesn'tReturnAnything 的情况呢? doSomething...每次都被评估?例如让 ClearCache = myCache.ClearItNow
  • 不,只在构造类型时执行一次。它类似于 C# 中的只读字段。每次调用都会是一个函数() -&gt; T;即,让 ClearCache () = myCache.ClearItNow ()
  • 好的,谢谢;我必须考虑这样一个事实,即参数的存在或不存在会改变 let 的含义:) 一开始,将 let 严格用于绑定和成员 this.foo() 用于方法可能对我来说更安全: )
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-14
  • 2015-02-11
  • 2015-06-04
  • 2014-09-07
  • 2013-09-02
相关资源
最近更新 更多