zoukankan      html  css  js  c++  java
  • 话说 type 之 let 绑定与 val 显式字段 F#

    今天和大家玩个找不同的游戏,先看看下面两段代码有什么不同,嘿嘿~。~

    type A() =
    let left = 0
    member x.Left = left
    type B =
    val private left : int
    new () = { left = 0 }
    member x.Left = x.left

    (有人要说了,类名不同,嘿嘿~。~)额 ><!

    其实我是想让大家注意

        member x.Left = left

        member x.Left = x.left

    ,看出了没?类B多了个 x.

    对于类B来说,如果去掉这个 x. 会报下面这个错误。

    The value or constructor 'left' is not defined

    难道说,let定义出的字段和val定义出的字段对于类的成员内部的可见性是不一样的?

    带着这个疑问,我研究了一下这两个类通过 .net reflector 转换后生成的 C# 代码,先贴出来:

    [Serializable, CompilationMapping(SourceConstructFlags.ObjectType)]
    public class A
    {
    // Fields
    internal int left = 0;

    // Properties
    public int Left
    {
    get
    {
    return this.left;
    }
    }
    }
    [Serializable, CompilationMapping(SourceConstructFlags.ObjectType)]
    public class B
    {
    // Fields
    internal int left@ = 0;

    // Properties
    [CompilationMapping(SourceConstructFlags.Field, 0)]
    internal int left
    {
    get
    {
    return this.left@;
    }
    }

    public int Left
    {
    get
    {
    return this.left@;
    }
    }
    }

    继续找不同,呵呵。

    我们看到的 class A 没啥特别的,class B 却有些许不同:

    在这里,我们先来理解一下 let 和 val 的意思

    MSDN 对 类中的 let 绑定的解释为: 可以通过使用类定义中的 let 绑定,为 F# 类定义私有字段和私有函数。
    MSDN 对类中的 val 的解释为: val 关键字用于在类类型或结构类型中声明字段,而无需将其初始化。通过此方式声明的字段称作“显式字段”。

    这两段解释在C#代码中体现的非常明显了,尤其是val,它其实已经定义好了一个 left 属性。如果去掉 type B 中 left 前面的 private, 则就可以将属性暴露出来了。

    但是令人费解的是,为什么我们自己定义的属性 Left 中的代码仍然是下面这样呢?

    return this.left@;

    像下面这样的代码才对啊

    return this.left

    其实,我们写的代码确实表达的是第二种情况,编译器对我们的代码进行了优化后,直接将 left@ 输出了,才形成了第一个代码。

    ============================================================

    最后,让我们看看 member 的语法和 type B 中那个蛋疼的 x.left。我先上个类

    type A() =
    member x.Hi = "Hi"
    member y.ReHi = y.Hi

    晕,怎么一会x一会y的? 结合 member 的语法看看吧。

    // Property that has get only.
    [ attributes ]
    [ static ] member [accessibility-modifier] [self-identifier.]PropertyName =
    get-function-body

    其实这里的x. y. 对应的是 [self-identifier.] 。如果不写,会返回一个错误

    This instance member needs a parameter to represent the object being invoked. Make the member static or use the notation 'member x.Member(args) = ...'

    白话一点说,就是你在 member 成员内部的代码中,需要给当前的类起个名字,常见的有起 this. 的,还有为了和C#中的 this. 不混淆而起 self. 的,然后要引用其他的成员时,需要用这个名字来指明。

    (但是如果是 static member,则不需要定义这个名字)

    而如果使用类内部的字段是,是不需要用这个 self-identifier 来指明的。

    所以,type B 中的 member x.Left = x.left 返回的是 left 属性而不是 left 字段。

    ============================================================

    最后,不得不说,这篇文章研究的东西有点蛋疼,不过您是不是也有所得呢?

  • 相关阅读:
    关于机器学习
    高级管理者和普通管理者区别
    一个kafka异常
    怎么读技术书
    Windows下查看什么进程占用文件
    关于Apache Phoenix和Cloudera结合
    bootstrap基础学习十一篇
    bootstrap基础学习十篇
    bootstrap基础学习九篇
    bootstrap基础学习八篇
  • 原文地址:https://www.cnblogs.com/softcat/p/2339323.html
Copyright © 2011-2022 走看看