gpt4 book ai didi

f# - 从继承的类构造函数中调用 lambda 函数中的基成员?

转载 作者:行者123 更新时间:2023-12-03 06:34:04 25 4
gpt4 key购买 nike

我有一个基类

type MyBase() =
let param = myfun()
member this.Param = param


type MyInherited() =
inherit MyBase()
do
base.Param.DoSomething() // cannot access base in let or do binding.

我想在继承的对象实例化过程中精确调用一次DoSomething。但在这里我不被允许。那我该怎么办?

我必须创建一个方法吗

     member this.DoSomething() = base.Param.DoSomething()

并在构造函数中调用它?

type MyInherited() as self =
inherit MyBase()
do
self.DoSomething()

感觉有点奇怪,而且重复

更新

我最初的简化示例并不合适。检查以下内容:

type MyBase() =
let param = "test"
member this.Param = param

type MyInherited() =
inherit MyBase()
do
(fun () -> base.Param) () |> ignore // Doesn't work,
// A protected member is called or 'base' is being used.
// This is only allowed in the direct implementation of members
// since they could escape their object scope.


type MyInherited() as self =
inherit MyBase()
do
(fun () -> self.Param) () |> ignore // Works

现在实际上好多了,我需要做的就是使用 self 而不是 base...(我不必重新定义 Param 因为它已经被继承了。)

F# 有这样限制的原因解释如下:

why is base only possible in private members?

但我仍然不清楚为什么 base 不能在闭包中使用,尽管它可以在简单的 let 绑定(bind)中访问。

最佳答案

您的初始代码完全有效。您不必首先定义一个调用基类的方法。

这有效:

do 
this.DoSomething()
member this.DoSomething() = base.DoSomething()

但这可以避免像您提到的那样重复:

do 
base.DoSomething()

这就是让你困惑的地方——构造函数不能有返回值。如果序列中的最后一个语句具有返回值,则 F# 假定该函数具有返回值/类型。但是,如果明确定义,这不会与方法签名相悖。因此,在这种情况下,F# 要求您明确表达您的意图。如果您的目的是放弃 base.DoSomething() 的返回,请使用 |> ignore 的管道到忽略运算符组合,如下所示:

do
base.DoSomething() |> ignore

让我们换一种说法,如果函数的目的返回一个没有副作用的值,并且如果这个值是因此没有使用,那么我们可以放心地得出结论,该函数不需要在构造函数中调用。因此编译器/交互式环境会警告您这一点。这就是 F# 在这里所鼓励的。

公平地说,这并不是显而易见的,除非您考虑以下因素:do compiles all such statements into the primary constructor 。如果您查看 constructor overloading 的 F# OO 风格可能会更清楚 unit * 签名的来源。

通常情况下,隐式定义返回值可以使编写函数变得更加流畅……正如 Rich Hickey 所说,现在只取决于熟悉程度。

  • 单位在其他语言中的另一个名称是void
<小时/>

更新

可能编译器约束以一种过于急切的方式应用,或者可能在幕后将 do 定义为一个闭包,然后由编译器展开并应用于构造函数。闭包能够看到 this,但方法/构造函数会获取 this 。这不是很直观,不是吗?您似乎发现了需要打磨的粗糙边缘。请考虑制作feature request 。 F# 现在完全开源,因此值得记录这样的案例。

我对此做了一个简短的练习。虽然 this 可以在构造函数中使用,但当存在重写时,这还不够。我认为以下可能是一个不错的前进方向(请参阅最后的new() block )。

[<AbstractClass>]
type MyBase() =
let letValue = "let value"
abstract Method : unit -> string
default this.Method() = "test"
member this.Method2() = "Param2"

type MyInherited(param : string) as this =
inherit MyBase()

// let localLetValue() = this.letValue // fails. let values are private members

do
//(fun () -> base.Param) () |> ignore // Error: The 'base' keyword is used in an invalid way. Base calls cannot be used in closures. Consider using a private member to make base calls.
(fun () -> this.Method) () |> ignore // succeeds -- takes local
(fun () -> this.base_Method) () |> ignore // succeeds -- takes base
(fun () -> this.Method2) () |> ignore // succeeds -- takes base

override this.Method() = "ABCdefHIJ"
member this.base_Method() = base.Method()

new() as this =
let a = base.Method() // succeeds
let b = this.Method() // succeeds
MyInherited("some value")

关于f# - 从继承的类构造函数中调用 lambda 函数中的基成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26346038/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com