F# 具有称为“类型扩展”的功能,使开发人员能够扩展现有类型。有两种类型的扩展:固有扩展和可选扩展。第一个类似于 C# 中的部分类型,第二个类似于方法扩展(但更强大)。
要使用内部扩展,我们应该将两个声明放入同一个文件中。在这种情况下,编译器会将两个定义合并为一种最终类型(即,这是一种类型的两个“部分”)。
问题是这两种类型对不同的成员和值有不同的访问规则:
// SampleType.fs
// "Main" declaration
type SampleType(a: int) =
let f1 = 42
let func() = 42
[<DefaultValue>]
val mutable f2: int
member private x.f3 = 42
static member private f4 = 42
member private this.someMethod() =
// "Main" declaration has access to all values (a, f1 and func())
// as well as to all members (f2, f3, f4)
printf "a: %d, f1: %d, f2: %d, f3: %d, f4: %d, func(): %d"
a f1 this.f2 this.f3 SampleType.f4 (func())
// "Partial" declaration
type SampleType with
member private this.anotherMethod() =
// But "partial" declaration has no access to values (a, f1 and func())
// and following two lines won't compile
//printf "a: %d" a
//printf "f1: %d" f1
//printf "func(): %d" (func())
// But has access to private members (f2, f3 and f4)
printf "f2: %d, f3: %d, f4: %d"
this.f2 this.f3 SampleType.f4
我阅读了 F# 规范,但没有找到任何想法为什么 F# 编译器区分值和成员声明。
在 F# 规范的 8.6.1.3部分中说“实例定义定义的函数和值在词法范围内(因此隐式私有)到正在定义的对象。”。部分声明可以访问所有私有成员(静态和实例)。我的猜测是,“词法范围”规范作者专门指的是“主要”声明,但这种行为对我来说似乎很奇怪。
问题是:这种行为是故意的,其背后的理由是什么?