簡體   English   中英

成員val和F#中的成員有什么區別?

[英]What is the difference between member val and member this in F#?

當我在F#中創建一個包含通用的,可變的.NET Stack的類時,如下例所示,該堆棧忽略了我推送它的任何東西。

open System.Collections.Generic

type Interp(code: int array) =
    member val PC = 0 with get, set
    member this.stack: Stack<int> = new Stack<int>() 
    member this.Code = code

let interp = Interp([|1;2;3|])
interp.stack.Push(1)
printfn "%A" interp.stack // prints "seq[]" WAT?!

然而,如果我通過屬性使堆棧可變:

open System.Collections.Generic

type Interp(code: int array) =
    member val PC = 0 with get, set
    member val stack: Stack<int> = new Stack<int>() with get, set 
    member this.Code = code

let interp = Interp([|1;2;3|])
interp.stack.Push(1)
printfn "%A" interp.stack // prints "seq[1]"

一切都像我期望的那樣神奇地起作用。

這到底是怎么回事? 我對以前語言(大多數是C#)的不變性的理解會說,即使第一個例子中的堆棧是一個不可變成員,這個不可變性應該只是參考(我不應該重新分配Stack本身)。 我仍然可以將值推送到/從中推送。 我錯過了什么,如果試圖改變該堆棧是錯誤的,為什么不拋出異常或編譯錯誤?

如果您嘗試編譯第一個版本,然后使用例如Reflector將其反編譯為C#,您將看到堆棧成員的定義如下:

public class Interp
{
    public Stack<int> stack
    {
        get { return new Stack<int>(); }
    }

    // Other members omitted for clarity...
}

如您所見,這也是有效的C#代碼,但顯然不是您想要的。

第二個版本交叉編譯成這樣的東西:

public class Interp
{
    internal int[] code;
    internal Stack<int> stack@;

    public Interp(int[] code) : this()
    {
        this.code = code;
        this.stack@ = new Stack<int>();
    }

    public Stack<int> stack
    {
        get { return this.stack@; }
        set { this.stack@ = value; }
    }

    // Other members omitted for clarity...
}

這看起來更像是你想要財產做的事情。

做一個你想要的更慣用的方法是:

open System.Collections.Generic

type Interp(code: int array) =
    let stack = Stack<int>()
    member val PC = 0 with get, set
    member this.Stack = stack
    member this.Code = code

如果您不需要在外部公開堆棧,請省略最后一行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM