我有一个基类
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.
Run Code Online (Sandbox Code Playgroud)
我想DoSomething在继承的对象实例化期间调用一次.但在这里我不被允许.那我该怎么办?
我是否必须创建一个方法
member this.DoSomething() = base.Param.DoSomething()
Run Code Online (Sandbox Code Playgroud)
并在构造函数中调用它?
type MyInherited() as self =
inherit MyBase()
do
self.DoSomething()
Run Code Online (Sandbox Code Playgroud)
感觉有点怪异,并且重复
我最初的简化示例不合适.检查以下内容:
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
Run Code Online (Sandbox Code Playgroud)
现在实际上它好多了,我需要做的就是使用self而不是base......(我不需要重新定义,Param因为它已经被继承了.)
这里解释了F#有这种限制的原因:
但是我仍然不清楚为什么base不能在闭包中使用它,尽管它可以通过简单的let绑定来访问.
您的初始代码完全有效.您不必首先定义一个调用基类的方法.
这有效:
do
this.DoSomething()
member this.DoSomething() = base.DoSomething()
Run Code Online (Sandbox Code Playgroud)
但这可以避免像你提到的重复:
do
base.DoSomething()
Run Code Online (Sandbox Code Playgroud)
这就是绊倒你的东西 - 构造函数不能有返回值.如果序列中的最后一个语句有返回,则F#假定该函数返回该值/类型的任何值.但是,如果明确定义,这不能与方法签名相反.所以F#要求你在这种情况下明确你的意图.如果你打算抛弃base.DoSomething()的返回,请使用管道到忽略运算符组合|> 忽略如下:
do
base.DoSomething() |> ignore
Run Code Online (Sandbox Code Playgroud)
让我们换个说法,如果一个功能的宗旨是无副作用返回一个值,而如果结果不使用这个值,那么我们可以有把握地断定该功能不需要在构造函数中调用.因此,编译器/交互式环境会向您发出警告.这就是F#在这里所鼓励的.
说句公道话,这不是很明显,除非你采取以下考虑:DO 编译所有这样的陈述到主构造.如果检查F#OO样式的构造函数重载,单元*签名的来源可能更清楚.
通常情况下,隐含定义的返回值会使编写函数变得更加流畅......正如Rich Hickey所说的那样,它现在只是熟悉了.
可能是一种编译器约束正在以过度的方式应用,或者可能是幕后的do被定义为闭包之前被解开并由编译器应用于构造函数.闭包可以看到这个,但是方法/构造函数得到了这个 和一个 基础.这不是很直观吗?看起来你已经找到了需要打磨的粗糙边缘.请考虑提出功能请求.F#现在是完全开源的,因此值得记录这样的案例.
我做了一个简短的练习.虽然这可以在构造函数中使用,但是当有覆盖时这是不够的.我认为以下可能是一个不错的前进方向(参见最后的new()块).
[<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")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1553 次 |
| 最近记录: |