8

次の 2 つのコードがあるとします。

def hello(z)
  "hello".gsub(/(o)/, &z)
end
z = proc {|m| p $1}
hello(z)
# prints: nil

def hello
  z = proc {|m| p $1}
  "hello".gsub(/(o)/, &z)
end
hello
# prints: "o"

これら 2 つのコードの出力が異なるのはなぜですか? ブロックがメソッド定義内で指定された場合と同じ方法で変数が評価されるようgsubに、メソッド定義の外からブロックを渡す方法はありますか?$1$2

4

4 に答える 4

3

なぜ出力が異なるのですか?

ruby の proc にはレキシカル スコープがあります。これは、定義されていない変数が見つかった場合、呼び出されたのではなく、プロシージャが定義されたコンテキスト内で解決されることを意味します。これにより、コードの動作が説明されます。

ブロックが正規表現の前に定義されていることがわかります。これは混乱を招く可能性があります。問題は魔法の ruby​​ 変数に関係しており、他の変数とはまったく異なる働きをします。@JörgWMittagを引用

それはかなり単純です。$SAFE がグローバル変数から期待されるように動作しない理由は、それがグローバル変数ではないからです。魔法のユニコーンの事だアマジギーです。

Ruby には魔法のようなユニコーンのようなものがありますが、残念ながらそれらは十分に文書化されていません (実際、まったく文書化されていません)。これは、別の Ruby 実装の開発者が難しい方法を発見したためです。これらのことはすべて異なる動作をし、(一見) 一貫性がありません。共通しているのは、グローバル変数のように見えますが、そのようには動作しないという 2 つの点だけです。

ローカル スコープを持つものもあります。スレッド ローカル スコープを持つものもあります。誰にも割り当てられずに魔法のように変化するものもあります。通訳者にとって魔法のような意味を持ち、言語の振る舞いを変えるものもあります。他の奇妙なセマンティクスが付加されているものもあります。

$1および変数がどのように機能するかを本当に知りたい場合は、$2見つけることができる唯一の「ドキュメント」はruby​​spec であると思います。これは、 Rubinusの人々によって困難な方法で行われた ruby​​ の仕様です。素敵なハッキングがありますが、痛みに備えてください。


$1、$2 変数を正しい方法で設定して、ブロックを別のコンテキストから gsub に渡す方法はありますか?

この次の変更で、あなたが望むものを達成することができます(しかし、あなたはすでにそれを知っているに違いありません)

require 'pp'
def hello(z)
  #z = proc {|m| pp $1}
  "hello".gsub(/(o)/, &z)
end
z = proc {|m| pp m}
hello(z)

その場でprocのスコープを変更する方法を知りません。しかし、あなたは本当にこれをしたいですか?

于 2013-08-31T17:01:36.133 に答える