7

私は、Ruby のクラス定義を再度開くことができるという印象を受けました。

class C
  def x
    puts 'x'
  end
end

class C
  def y
    puts 'y'
  end
end

これは期待どおりにy機能し、元のクラス定義に追加されます。

次のコードが期待どおりに機能しない理由がわかりません。

class D
  x = 12
end

class D
  puts x
end

これにより、NameError例外が発生します。クラスが再開されたときに新しいローカル スコープが開始されるのはなぜですか? これは少し直感に反するようです。クラスが拡張されたときに以前のローカルスコープを継続する方法はありますか?

4

4 に答える 4

8

ローカル変数はオブジェクトに関連付けられているのではなく、スコープに関連付けられています。

ローカル変数はレキシカル スコープです。あなたがやろうとしていることは、以下よりも有効ではありません:

def foo
  x = :hack if false  # Ensure that x is a local variable
  p x if $set         # Won't be called the first time through
  $set = x = 42       # Set the local variable and a global flag
  p :done
end

foo                   #=> :done 

foo                   #=> nil (x does not have the value from before)
                      #=> done

上記では、同じオブジェクトの同じメソッドが両方とも実行されています。はself変更ありません。ただし、ローカル変数は呼び出しの間にクリアされます。

クラスを再度開くことは、メソッドを再度呼び出すようなものです。同じselfスコープ内にいますが、新しいローカル コンテキストを開始しています。class Dでブロックを閉じるとend、ローカル変数は破棄されます ( で閉じられていない限り)。

于 2012-05-04T16:44:27.073 に答える
6

ruby では、ローカル変数は定義されているスコープ内でのみアクセス可能です。ただし、classキーワードにより、まったく新しいスコープが発生します。

class D
  # One scope
  x = 12
end

class D
  # Another scope
  puts x
end

したがって、最初のセクションで定義されたローカル変数にアクセスすることはできません。class最初のスコープを離れると、内部のローカル変数が破棄され、ガベージ コレクションによってメモリが解放されるためです。

defこれは、たとえば にも当てはまります。

于 2012-05-04T16:38:11.600 に答える
0

簡単な解決策は、xクラス インスタンス変数にすることです。もちろん、これはスコープの質問には答えません。xが再度開かれたクラスのスコープ( Ruby 変数のスコープを検出するを参照) に含まれていない理由は、そもそもそのスコープがクラスDのスコープではなかったからだと思います。xはインスタンス変数でもクラス変数でもないため、クラスDが閉じられたときにxのスコープは終了しました。

それが役立つことを願っています。

于 2012-05-04T16:46:54.170 に答える
0

この動作が理にかなっている理由の一部は、メタプログラミング機能にあります。新しい定数に名前を付けたり、メソッド名を参照したりするために使用できるデータを格納するために、いくつかの一時変数を使用できます。

class A
  names, values = get_some_names_and_values()

  names.each_with_index do |name, idx|
    const_set name, value[idx]
  end
end

または、固有クラスを取得する必要があるかもしれません...

class B
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    ...
  end
end

クラスを再度開くたびに新しいスコープを持つことは理にかなっています。なぜなら、Ruby では実際に実行されるコードであるクラス定義内にコードを記述することが多く、クラスを開くこと単に の正しい値を取得する方法に過ぎないからですself。クラスのコンテンツがこれらの変数によって汚染されないようにする必要があります。それ以外の場合は、クラス インスタンス変数を使用します。

class C
    @answer = 42
end

class C
  p @answer
end
于 2012-05-04T17:08:28.050 に答える