3

変数スコープがIoでどのように機能するかはよくわかりません。ドキュメントにはクロージャーがあると書かれていますが、メソッドidx内から見ることができないようです。親の可視性はクロージャーの重要な前提ですが、どのように機能するのでしょうか?nextprev

List iterator := method(
    idx := 0

    itr := Object clone
    itr next := method(
        idx = idx + 1
        return self at(idx)
    )

    itr prev := method(
        idx = idx - 1
        return self at(idx)
    ) 

    return itr
)

これはどのように達成されるべきですか?

4

1 に答える 1

7

つまり、メソッドとブロックがどのように機能するかを根本的に誤解していますが、それは問題ありません。基本を見てみましょう:

  1. メソッドは、名前で呼び出すとアクティブになり、スコープが nil に設定されているブロックです。スコープについて話すとき。
  2. ブロックのスコープは、ブロックが作成されたコンテキストに設定されています。

context は locals オブジェクト、基本的にはスタック フレームを意味します。スコープとは、ブロック/メソッドが呼び出されたときに、誰がブロック アクティベーションの「送信者」になるかを意味します。call senderメソッドまたはブロックのコンテキスト内のオブジェクトによってこれにアクセスできます。

それでは、コードを見てみましょう。ほぼ完璧です。欠けているのは 1 つだけで、明らかではありません。

メソッドには動的スコープがあるため、そのscopeメッセージは nil を返します。これは、そのメッセージを受信したオブジェクトが送信コンテキストとして渡されるべきであることをエバリュエーターに示します。私たちはその動作を望んでいません。特定のスコープ、特にiter定義したメソッドのローカルをキャプチャしたいのです。修正された例を見てみましょう。

List iterator := method(
    idx := 0

    itr := Object clone
    itr next := method(
        idx = idx + 1
        at(idx)
    ) setScope(thisContext)

    itr prev := method(
        idx = idx - 1
        at(idx)
    ) setScope(thisContext)

    itr
)

本文を簡素化しましたが、機能面で変更はありません (メッセージ送信数が少ないことを除けば)。重要なのは、/setScopeへの割り当ての前にメソッドに渡される呼び出しです。これを次のように書き直すこともできました。nextprev

iter prev := block(
    idx = idx - 1
    at(idx)
) setIsActivatable(true)

しかし、ブロックはデフォルトではアクティブ化できないため、ブロックをアクティブ化する必要がありました。上記のコードと修正されたitr prev使用法method()は、機能的に同等です。

メソッドはクロージャではなく、ブロックです。ブロックは単にスコープが非 nil のメソッドであり、同じオブジェクトです。

于 2013-11-12T21:53:46.903 に答える