28

さて、F# は参照 (ある種の C++ のような参照) を管理できることを理解するようになりました。これにより、関数に渡されるパラメーターの値を変更できるようになり、プログラマーが複数の値を返すことも可能になります。ただし、ここに私が知る必要があるものがあります:

  1. Ref キーワード: キーワードrefは、値から、推論された型のその値への参照を作成するために使用されます。そう

    let myref = ref 10
    

    Ref<int>これは、F#が (変更可能なフィールドに) my を置く型のオブジェクトを作成することを意味しますint 10

    わかった。したがって、それがタイプrefのインスタンスを作成するために使用されると思います。Ref<'a>それが正しいか?

  2. 値へのアクセス: 参照に格納されている値にアクセスするには、次のようにします。

    let myref = ref 10
    let myval = myref.Value
    let myval2 = !myref
    

    オペレーターは、:=次のように値を編集できるようにします。

    let myref = ref 10
    myref.Value <- 30
    myref := 40
    

    したがって!、(Bang) は私の参照を逆参照します。そしてそれ:=を編集します。これも正しいと思います。

  3. & 演算子: この演算子は何をしますか? 参照型に適用されますか? いいえ、変更可能な値に適用する必要があると思いますが、これは何を返しますか? 参照?住所・アドレス?インタラクティブを使用する場合:

    let mutable mutvar = 10;;
    &a;;
    

    &最後の行でエラーがスローされるため、演算子の目的がわかりません。

  4. ByRef: はどうbyrefですか?それは私にとって非常に重要なことですが、私はそれを理解していないことに気づきました。パラメータの受け渡しに関する関数で使用されていることを理解しています。渡された値を編集できるようにしたい場合は byref を使用します (これは関数型言語の哲学に少し反しますが、f# はそれ以上のものです)。次の点を考慮してください。

    let myfunc (x: int byref) =
        x <- x + 10
    

    変ですね。let myref = ref 10参照があり、これを実行して値を編集すると、次のmyref <- 10ようになるためエラーが発生することを私は知っています: myref := 10。しかし、その関数で演算子xを使用して編集できるということは、それは参照ではないということですよね?<-x

    それが参照ではないと仮定するとx、関数でパラメーターを使用byrefするときに、そのパラメーターに変更可能な構文を適用できると仮定します。したがって、これは構文の問題であり、これで問題ないと仮定すると、実際にはすべてが機能します (コンパイラ エラーは発生しません)。しかし、何xですか?

  5. 関数の呼び出し: byref パラメーターを使用する関数を使用するにはどうすればよいですか?

    &オペレーターが関与していますが、これについてもっと詳しく説明していただけますか? この記事: MSDN のパラメーターと引数では、次の例が提供されています。

    type Incrementor(z) =
        member this.Increment(i : int byref) =
           i <- i + z
    
    let incrementor = new Incrementor(1)
    let mutable x = 10
    // A: Not recommended: Does not actually increment the variable. (Me: why?)
    incrementor.Increment(ref x)
    // Prints 10.
    printfn "%d" x  
    
    let mutable y = 10
    incrementor.Increment(&y) (* Me: & what does it return? *)
    // Prints 11.
    printfn "%d" y 
    
    let refInt = ref 10
    incrementor.Increment(refInt) (* Why does it not work in A, but here it does? *)
    // Prints 11.
    printfn "%d" !refInt
    
4

1 に答える 1

32

Refキーワードはい、あなたが書くとき、let a = ref 10あなたは本質的にタイプが可変フィールドを持っているlet a = new Ref<int>(10)ところに書いています。Ref<T>Value

アクセス値:=and演算子は、次の!ように記述するための単なるショートカットです。

a.Value <- 10  // same as writing: a := 10
a.Value        // same as writing: !a

ByRefは、メソッドパラメータでのみ(合理的に)使用できる特殊なタイプです。これは、引数が本質的に(ヒープまたはスタックに割り当てられた)メモリ位置へのポインタであるべきであることを意味します。outこれは、C#のref修飾子に対応します。このタイプのローカル変数は作成できないことに注意してください。

&演算子は、型を期待する関数/メソッドに引数として渡すことができる値(ポインター)を作成する方法byrefです。

メソッドにローカルの可変変数への参照を渡すため、関数の例を呼び出すbyrefとうまくいきます。参照を介して、メソッドはその変数に格納されている値を変更できます。

以下は機能しません。

let a = 10            // Note: You don't even need 'mutable' here
bar.Increment(ref a)  

その理由は、の新しいインスタンスを作成していて、の値をこのインスタンスRef<int>にコピーしているためです。a次に、Incrementメソッドはのインスタンスでヒープに格納されている値を変更しますがRef<int>、このオブジェクトへの参照はもうありません。

let a = ref 10
bar.Increment(a)  

aはtypeの値でありRef<int>、ヒープに割り当てられたインスタンスへのポインタを渡し、を使用してヒープにIncrement割り当てられた参照セルから値を取得するため、これは機能します!a

ref(コンパイラはこのケースを特別に処理するため、引数としてを使用して作成された値を使用できます。これは便利なシナリオであるためbyref、フィールドを自動的に参照しValueます...)。

于 2011-02-17T11:54:02.020 に答える