从静态成员访问let绑定字段 [英] Accessing let bound fields from static members

查看:92
本文介绍了从静态成员访问let绑定字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以访问静态成员的let绑定字段?下面给出了指示的错误:

Is there any way to access let bound fields from a static member? The following gives the indicated error:

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
        ()

私有显式字段确实允许来自静态成员的访问:

Whereas private explicit fields do allow access from static members:

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

文档 http://msdn.microsoft.com/zh-cn/library/dd469494.aspx 指出显式字段不用于常规用途",但是从静态成员访问私有实例字段无疑是一种常规情况.而且,我不相信您可以在主构造函数中设置显式字段,这意味着即使需要从静态成员访问一个私有实例字段,也必须将所有字段移到显式字段,并且您不能再使用主要的构造函数-全部或全部.

The documentation http://msdn.microsoft.com/en-us/library/dd469494.aspx states that "Explicit fields are not intended for routine use," yet accessing private instance fields from static members is certainly a routine scenario. Moreover, I don't believe you can set explicit fields within a primary constructor, which means if even one private instance field needs to be accessed from a static member, all of your fields must be moved over to explicit fields and you can no longer use a primary constructor -- it's all or nothing.

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

As real world example where you would actually want to access a private instance field from a static member, consider a big integer implementation: a BigInteger class would be immutable, so the internal representation of the big integer would kept as a private instance field (let's call it data). Now, suppose you felt an Add(other) instance method was inappropriate for an immutable data structure and you only wanted to implement a static Add(lhs,rhs) method: in this case, you would need to be able to access lhs.data and rhs.data.

推荐答案

我认为您无法做到这一点...实际上,您也无法从其他实例访问让值绑定的值:

I don't think you can do that... in fact, you can't access let-bound values from other instances either:

type Foo() =
  let x = 3
  member this.Test(f:Foo) =
    f.x // same error

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

In general, if you need to access such a value from outside of the instance it belongs to, you should probably either create a private property to get the value or use a private field instead.

更新 第8.6.2节规格.特别是:

实例"let"绑定在词法上作用于定义的对象(因此隐式私有).

Instance "let" bindings are lexically scoped (and thus implicitly private) to the object being defined.

也许F#团队的某人会就该语言为何如此行事给出明确的答案.但是,我可以想到一些潜在的原因:

Perhaps someone from the F# team will weigh in with a definitive answer as to why the language behaves this way. However, I can think of a couple of potential reasons:

  1. 约束范围的值甚至可能不作为字段出现(例如,再次从规范中来看,let绑定将由构造函数的局部变量表示.如果该值不是语法函数,则是不可变的并且不被使用任何职能或成员")
  2. 这似乎与语言中其他地方的let绑定的行为一致.请参阅大致等同的类和记录定义的示例,这些示例将在以后进行介绍(因为我似乎无法正确格式化有序列表中的代码块...)
  3. 与许多其他语言相比,这提供了更精细的封装级别-绑定对于所定义的对象而言是本地的.通常,其他实例不需要访问这些绑定,在这种情况下,最好不要公开它们.
  4. 如果您希望某些东西可以被您的类的其他实例访问(或从静态方法中),则有一种简单的方法可以做到这一点-创建一个私有字段或属性,以明确表达您的意图,即值可以从您所在的实例外部访问.

如前所述,这是创建记录的大致等效的类定义和方法:

As mentioned earlier, here are a roughly equivalent class definition and method to create a record:

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

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

Since constructors in F# are conceptually similar to any other function which returns an instance of a type (e.g. they can be called without using new), calling MyClass 5 is conceptually similar to calling makeMyRecord 5. In the latter case, we clearly don't expect that there is any way to access the local let binding for j from another instance of the record. Therefore, it's consistent that in the former case we also don't have any access to the binding.

这篇关于从静态成员访问let绑定字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆