标题中的错误含糊不清,但googling it目前在SO上有两次点击,共有5次点击(表明它是一种罕见的野兽,所以不要指望这里有太多的访问;)。我希望这个问题在该列表中排在第六位:p。
Kvb's answer in this thread表明错误文本具有误导性,如果从闭包内调用base,则会引发错误文本,但这种情况并非总是如此,因为这有效:
// in a closure, but no FS0419
let myObj = fun foo ->
{ new obj() with override this.ToString() = base.ToString() + foo}
但这失败了(我发现这个问题的最简单方法):
// not in a closure, but raises FS0419
let myObj =
{ new obj() with override this.ToString() = () |> base.ToString }
我使用对象表达式而不是带继承的类型声明,我尝试通过构建自定义NUnit约束来创建新的FsUnit约束。这是一个简化版本,显示了我看到的问题:
let EndsWithIgnoreWhitespaceContraint expectedResult =
{ new EndsWithConstraint(expectedResult) with
override __.ApplyTo<'T> (actual: 'T) =
let actual = box actual
if actual :? string then
actual :?> string
|> fun s -> if isNull s then String.Empty else s
|> fun s -> s.Trim()
// error FS0419: 'base' values may only be used to make direct
// calls to the base implementations of overridden members
|> base.ApplyTo
else
exn "String expected .. bla bla..." |> raise }
// make it available to FsUnit's syntax style (overriding existing endWith)
let endWith = EndsWithIgnoreWhitespaceContraint
// using it:
" hello world " |> should endWith "world"
现在,显然没有必要知道FsUnit看到这种行为。但是我花了一个晚上和一天才意识到自己被骗了,事实上直到我在SO上写这个问题才看到它。
事实证明这是有效的:
而不是x |> base.SomeMethod
写base.SomeMethod x
。
我觉得这很令人惊讶。不确定它是一个bug还是一个功能。但是由于|>
运算符是内联的(我用不同的运算符测试它)并且它没有创建新函数(如>>
那样),我不明白为什么会出现这个错误。
事实上,我认为f a
和a |> f
之间没有任何语义差异(除了优先规则之外)。那么为什么会出错呢?我打破了什么规则?
最后一个想法,kvb写道“base
无法从闭包调用... curried成员自动创建一个闭包”,这表明这是错误的,但它编译得很好:
let myObj foo bar =
{ new obj() with override this.ToString() = base.ToString() + foo + bar}
是否有人确切知道导致此错误的原因是什么?
答案 0 :(得分:2)
首先,您误解了“ base不能用于闭包”的答案。它的意思是引用一个捕获基础本身的闭包 - 它是阻止它工作的捕获,而不是闭包。在{ new obj }
示例中,任何闭包都不会捕获base
。捕获整个对象,但base
仅在ToString
方法中直接使用。
为了说明,试试这个:
let myObj =
{ new obj() with override this.ToString() = (fun() -> base.ToString())()}
此代码无法编译,因为base
正在捕获fun() -> base.ToString()
。
其次,使用对象方法作为函数不能像人们预期的那样“直接”工作,因为.NET方法的表示方式与F#函数不同。相反,当遇到类似let x = obj.M
的东西时,编译器会将其视为let x = fun a -> obj.M(a)
- 也就是说,将其包装在闭包中。
为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
let f = base.ToString // Error here
f()
}
看看这是怎么回事? : - )
当您管道对象方法时,编译器必须创建该闭包,然后将其传递给管道运算符。为了说明,试试这个:
let myObj =
{ new obj() with
override this.ToString() =
() |> base.ToString // Same error
}