首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么F#构造函数中的"let“创建私有成员而不是局部变量

为什么F#构造函数中的"let“创建私有成员而不是局部变量
EN

Stack Overflow用户
提问于 2022-02-01 05:52:48
回答 1查看 107关注 0票数 3

我正在学习一些F#,并试图弄清楚构造函数是如何工作的。

我想编写一个类,它接受一些输入数据,对其进行分析,并通过成员变量将结果提供给外部世界。解析过程并不简单,所以我希望在此过程中创建一些局部变量,但是如果不将它们变成私有成员变量,我又如何做到这一点呢?使用let创建私有成员变量的almost the same就是使用member private,但我不希望这些临时变量污染对象的命名空间。

到目前为止,这是我能想到的最好的:

代码语言:javascript
复制
type MyClass( inputData ) = 

    let _parsedData = 
        // simulate expensive parsing of the input data
        let work = sprintf "< %s >" inputData
        sprintf "[%s]" work

    member this.parsedData = _parsedData

    member this.dump () = 

        // this doesn't compile (as expected)
        //printfn "work = %s" work

        // I want this to *not* compile (because _parsedData is a local variable in the constructor)
        printfn "_parsedData = %s" _parsedData

[<EntryPoint>]
let main argv = 
    let obj = MyClass "hello, world!"
    printfn "obj.parsedData = %s" obj.parsedData
    obj.dump()
    0 

但是_parsedData变成了私有成员变量,这是不必要的,因为它只是一个临时的工作变量,最后的值存储在this.parsedData中。上面链接到的SO post表明,使用let创建的变量将充当局部变量并被丢弃,只要在其他成员中没有引用它们,但是定义this.parsedData返回_parsedData的操作就足以保持_parsedData存活。

我可以使用惰性评估:

代码语言:javascript
复制
let _parsedDataLazy = lazy ( 
    // simulate expensive parsing of the input data
    let work = sprintf "< %s >" inputData
    sprintf "[%s]" work
) 

member this.parsedDataLazy = _parsedDataLazy.Value

但是这并没有真正的帮助,因为它仍然存在_parsedDataLazy成为私有成员变量的问题(尽管在这种情况下,这是有意义的)。这种方法还意味着在第一次调用inputData之前保持parsedDataLazy活动,这可能是不可取的/不可能的。

我还想过使用val来定义成员变量,然后执行解析代码来填充它,但是do绑定必须出现在任何member的:-/之前。

我只希望能够在构造函数中使用局部变量,计算值,然后将其存储在对象中。既然已经有了这样的方法,为什么let要创建一个私有成员变量?!构造函数的目的是初始化正在创建的对象,它只是一个函数,因此我不明白为什么在什么时候可以执行代码或不同的行为(例如,如果我使用let在成员函数中定义一个新变量,它就不会作为成员变量被悬挂到对象中)。

另外,如果我使用let在构造函数中创建一个私有成员变量,如下所示:

代码语言:javascript
复制
let _foo = 42

然后我就这样访问它:

代码语言:javascript
复制
let member this.printFoo () =
    printfn "_foo = %s" _foo // no "this"

但如果我像这样创造它:

代码语言:javascript
复制
member private _foo = 42

然后我就这样访问它:

代码语言:javascript
复制
let member this.printFoo () =
    printfn "_foo = %s" this._foo // uses "this"

这种不同的语法表明,前者是在构造函数上创建闭包,并使_foo变量在对象的生命周期内保持活动状态,而不是_foo实际上是对象的成员。这就是真正发生的事吗?

EN

回答 1

Stack Overflow用户

发布于 2022-02-01 09:04:17

要回答@konst-sh的问题:“为什么你认为应该对每个电话进行评估?”,我不认为应该这样做,但这不是我所看到的。

我的理解是,对于下面的代码,组成parsedData的3个语句是一个表达式,它的计算结果是一个字符串(sprintf的输出),该字符串存储在一个成员变量中。

代码语言:javascript
复制
type MyClass( inputData ) =

    member this.parsedData =
        // simulate expensive parsing of the input data
        printfn "PARSE"
        let work = sprintf "< %s >" inputData
        sprintf "[%s]" work

[<EntryPoint>]
let main argv =
    let obj = MyClass "hello, world!"
    printfn "CONSTRUCTED"
    printfn "obj.parsedData = %s" obj.parsedData
    printfn "obj.parsedData = %s" obj.parsedData
    0

但当我运行它时,我得到了这个:

代码语言:javascript
复制
CONSTRUCTED
PARSE
obj.parsedData = [< hello, world! >]
PARSE
obj.parsedData = [< hello, world! >]

我希望看到这样的情况:

代码语言:javascript
复制
PARSE
CONSTRUCTED
obj.parsedData = [< hello, world! >]
obj.parsedData = [< hello, world! >]

逐步进入VSCode还可以确认这3条语句被执行了两次。但是parseData不是一个函数,对吗?为此,我需要这样定义:

代码语言:javascript
复制
    member this.parsedData () =
        ...

感觉好像我错过了一些最基本的东西。:-)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70936102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档