从静态成员访问let bound字段

Ste*_*sen 9 f#

有没有办法从静态成员访问let绑定字段?以下给出了指示的错误:

type Foo(x) =
    let x = x
    static member test() =
        let foo = Foo(System.DateTime.Now.Month)
        printfn "%A" foo.x //the field, constructor or member 'x' is not defined
        ()
Run Code Online (Sandbox Code Playgroud)

私有显式字段允许从静态成员访问:

type Bar =
    val private x:int
    new(x) = { x=x }
    static member test() =
        let Bar = Bar(System.DateTime.Now.Month)
        printfn "%A" Bar.x
        ()
Run Code Online (Sandbox Code Playgroud)

文档http://msdn.microsoft.com/en-us/library/dd469494.aspx声明"显式字段不适合日常使用",但从静态成员访问私有实例字段当然是一种常规方案.此外,我不相信您可以在主构造函数中设置显式字段,这意味着如果需要从静态成员访问一个私有实例字段,则必须将所有字段移动到显式字段,并且您不能再使用主要构造函数 - 它是全有或全无.

作为真实想要从静态成员访问私有实例字段的实际示例,请考虑一个大整数实现:BigInteger类是不可变的,因此大整数的内部表示将保留为私有实例字段(让我们叫它data).现在,假设您认为Add(other)实例方法不适合不可变数据结构,并且您只想实现静态Add(lhs,rhs)方法:在这种情况下,您需要能够访问lhs.datarhs.data.

kvb*_*kvb 7

我认为你不能这样做......事实上,你不能从其他实例访问let-bound值:

type Foo() =
  let x = 3
  member this.Test(f:Foo) =
    f.x // same error
Run Code Online (Sandbox Code Playgroud)

通常,如果您需要从它所属的实例外部访问这样的值,您应该创建一个私有属性来获取值或使用私有字段.

更新规范的第8.6.2节对此进行了介绍.特别是:

实例"let"绑定在词法范围内(因此隐式私有)到正在定义的对象.

也许来自F#团队的人会对这种语言行为的确切答案进行权衡.但是,我可以想到几个潜在的原因:

  1. let-bound值甚至可能不作为字段出现(例如,再次来自规范,let绑定将由构造函数的local表示)如果值不是语法函数,则不可变且不在任何函数中使用或成员")
  2. 这似乎与该语言中其他地方的绑定行为一致.查看大致相同的类和记录定义的示例,我将其进一步包含在内(因为我似乎无法在有序列表中正确格式化代码块...)
  3. 与其他许多语言相比,这提供了更细粒度的封装级别 - 绑定是定义对象的本地绑定.通常,其他实例不需要访问这些绑定,在这种情况下,不暴露它们是很好的.
  4. 如果你想要一些可以被你的类的其他实例(或者从静态方法中)访问的东西,那么有一种简单的方法可以做到这一点 - 创建一个私有字段或属性,这有利于明确表达你的意图值可访问来自您所在实例的外部.

如前所述,这里是一个大致相同的类定义和创建记录的方法:

type MyClass(i:int) =
  let j = i * i
  member this.IsSameAs(other:MyClass) = 
    false // can't access other.j here

type myRecord = { isSameAs : myRecord -> bool }
let makeMyRecord(i:int) =
  let j = i * i
  { isSameAs = (fun r -> false) } //obviously, no way to access r.j here
Run Code Online (Sandbox Code Playgroud)

由于F#中的构造函数在概念上类似于返回类型实例的任何其他函数(例如,它们可以在不使用的情况下new调用),因此调用MyClass 5在概念上类似于调用makeMyRecord 5.在后一种情况下,我们显然不希望有任何方法可以j从另一个记录实例访问本地let绑定.因此,在前一种情况下我们也没有任何访问绑定的一致性.