web-dev-qa-db-ja.com

let、member val、member thisはいつ使用しますか?

F#には、変数やメンバーを型で定義するためのさまざまな方法があります。 letmember valおよびmember this. F#では、それらの違いは何ですか?静的メンバーと可変メンバーはどうですか?

39
rightfold

@meziantouからの回答では、オプションの概要(およびオプションの動作の違い)がすでに示されているので、簡単な要約または推奨事項のリストを示します。

  • タイプ内でのみ表示されるローカル値(基本的にはletフィールドまたはprivate関数)を定義する場合は、privateまたは_let mutable_を使用します。トップレベルのモジュール内では、これらはパブリックにアクセス可能で、一度評価されます。モジュールレベルの_let mutable_は、バッキング値のない単一の書き込み可能なフィールドを作成します。

  • valを使用して自動プロパティを作成できます。これは_member val Foo = .. with get_の略です。 F#から、これはフィールドと見なされますが、変更を防ぐためにバッキングフィールドを持つgetプロパティとして内部的に実装されています。

  • _val mutable_を使用してパブリックフィールドを定義できますが、実際にパブリックフィールドが必要でない限り、これはお勧めしません(たとえば、一部の.NETライブラリでは、この構造の型が必要になる場合があります)。

  • _member x.Foo = ..._を使用することは、型から状態を(読み取り専用で)公開するための最良の方法です。ほとんどのF#型は不変であるため、おそらくこれが最も一般的なパブリックメンバーです。取得専用のインスタンスプロパティの略です。

  • member x.Foo with get() = .. and set(value) ...の使用は、ゲッターとセッターで独自のカスタムコードを使用してget/setプロパティを作成する必要がある場合に役立ちます。これは、変更可能なオブジェクトを作成するときに便利な場合があります。

  • _member val Foo = ... with get, set_の使用は、基本的にはC#で自動実装されるプロパティと同じです。これは、可変のバッキングフィールドを読み書きするゲッターとセッターを持つ可変のプロパティが必要な場合に便利です。

  • 型で_static let_を使用すると、静的(クラスレベル)の読み取り専用フィールドが作成されます。これは、バッキングフィールドを持つプロパティを内部的に作成します。バッキングフィールドのない読み取り/書き込み静的フィールドには、_static mutable let ..._を使用します。

  • _static val mutable private_を使用すると、バッキングフィールドを持つ静的な読み取り/書き込み自動プロパティが作成され、パブリックにすることはできません。

52
Tomas Petricek

何が起こっているのかを逆コンパイルする方が簡単であることがわかりました。

type Region() =
  let mutable t = 0.0f
  member val Width = 0.0f
  member x.Height = 0.0f
  member val Left = 0.0f with get,set
  member x.Top with get() = 0.0f and set(value) = t <- value

実際には次のとおりです。

public class Region
{
    internal float t;

    internal float Width@;

    internal float Left@;

    public float Width
    {
        get
        {
            return this.Width@;
        }
    }

    public float Height
    {
        get
        {
            return 0f;
        }
    }

    public float Left
    {
        get
        {
            return this.Left@;
        }
        set
        {
            this.Left@ = value;
        }
    }

    public float Top
    {
        get
        {
            return 0f;
        }
        set
        {
            this.t = value;
        }
    }

    public Region() : this()
    {
        this.t = 0f;
        this.Width@ = 0f;
        this.Left@ = 0f;
    }
}
23
foobarcode

このサンプルでは、​​構文の違いについて説明します。

type MyClass() =
    let random  = new System.Random() 
    [<DefaultValue>] val mutable field : int
    member val AutoProperty = random.Next() with get, set
    member this.ExplicitProperty = random.Next()

let c = new MyClass()
// c.random is not accessible
c.field <- 42 // 'field' is accessible

// An automatic property is only evaluated upon initialization, and not every time the property is accessed
printfn "AutoProperty = %d" c.AutoProperty // x
printfn "AutoProperty = %d" c.AutoProperty // Still x

// The value of the explicit property is evaluated each time
printfn "ExplicitProperty = %d" c.ExplicitProperty // y
printfn "ExplicitProperty = %d" c.ExplicitProperty // The value is re-evaluated so you'll get a different value
13
meziantou