在此被标记为重复之前:我知道这个问题与使用单位作为类型参数时有关编译错误的各种问题有关。一些例子:
- Why is unit用作通用接口参数时,F# 类型系统会以不同方式对待吗? https://stackoverflow.com/q/26296401/4191347
- F# 接口因单位继承失败 https://stackoverflow.com/q/4485445/4191347
- 使用单位作为类型参数和重写方法 https://stackoverflow.com/q/10012078/4191347
这些都遇到了与此类似的问题:
type Interface<'a> =
abstract member MyFunc : unit -> 'a
let implementingInstance =
{ new Interface<_> with
member __.MyFunc () = () } // Compiler error!
据我了解,代码无法编译,因为返回单位的函数是用void
内部返回,这是 CLI 的额外功能而不是类型。
然而!以下似乎使编译器满意:
type RecordVersion<'a> =
{ MyFunc : unit -> 'a }
let recordInstance =
{ MyFunc = ignore }
如果我替换这也有效ignore
与 lambda 或let
绑定模块功能。
对我来说,这只是同一件事的另一种表述。 (尽管与 F# 设计指南不一致,该指南建议优先选择接口而不是携带函数的记录类型。)
我对设计由用户指定所使用的行为和类型的 API 感兴趣。因此,我希望避免发生意外和令人困惑的编译器错误。但我不太确定该怎么做。看起来像 F# 的“函数式”函数do将单位视为一种类型。
单位出现此类虚假误差的确切条件是什么?我可以通过打破设计准则并使用函数记录而不是接口来避免 API 中出现这些问题吗? (我不太介意,但我不确定它是否能永远解决问题。)
我相信规则是静态已知具有返回类型的方法unit
将被编译为具有返回类型的 .NET 方法void
在 .NET 类型系统中(所谓静态已知,是指与泛型方法或泛型类型上使用类型参数作为返回类型的方法相比)。在调用时,编译器隐藏返回方法之间的区别void
以及返回 true 的方法unit
CLR 级别的值。
您的示例中出现问题是因为正确实现通用接口实际上需要unit
CLR 级别的返回类型(并且 CLR 确实关心两者之间的区别)unit
and void
)。换句话说,当且仅当您想通过静态已知返回的方法覆盖返回泛型类的类型参数的方法时,才会出现问题unit
(基于替换unit
对于该类型参数)。这里的重写是指在类或接口上实现抽象方法,或者在类上重写非密封方法。
正如 Tamil 指出的,解决此限制的一种方法是确保使用 F# 函数而不是方法。另一种解决方法是在层次结构中引入一个额外的具体类,该类具有虚拟泛型类型参数(假设额外的类是T<'unit>
),并返回Unchecked.defaultof<'unit>
代替()
任何会引起问题的地方。然后你可以派生一个额外的非泛型具体类T
from T<unit>
一切都会很好。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)