5

CoffeeScript では:

f = ->
  v = 5
  g = ->
    v
  g()

f() # returns 5 as expected

ルビーの場合:

def f
  v = 5
  def g
    v # undefined local variable or method `v' for main:Object (NameError)
  end
  g
end
f

どうやら JavaScript 関数は、変数が作成されたスコープ内の変数をキャプチャするように設定されているようですが、Ruby のメソッドはそうではありません。この点で、Ruby メソッドを JavaScript 関数のように動作させる方法はありますか?

4

5 に答える 5

9

Ruby には、スクリプト スコープ、モジュール/クラス/メソッド定義スコープ、およびブロック スコープがあります。ブロックのみがネストされたスコープを作成します。したがって、ブロックを使用してメソッドを定義する必要があります。ありがたいことに、ブロックを取るメソッドを定義するメソッドがあります。

def f
  v = 5
  define_method :g do
    v
  end
  g
end
f
# => 5

ただし、これはあなたが思っていることをしないことに注意してください (元のコードもそうではありません)。methodにネストされたメソッドを定義しませ。Ruby にはネストされたメソッドがありません。メソッドは常にモジュールに属し (クラスはモジュールです)、メソッドに属することはできません。gf

これが行うことは、メソッドをf定義することです。これを実行すると、メソッドが定義され、gそのメソッドが呼び出されます。

観察:

methods.include?(:g)
# => true

と呼ばれる新しいトップレベル メソッド (実際には のプライベート インスタンス メソッドObject)gを定義しましたf

おそらく必要なのはラムダです:

def f
  v = 5
  g = -> { v }
  g.()
end
f
# => 5

あなたが書いた別の回答へのコメントで:

さて、私はラムダをいじっています.私がv内部に行ったことは、一度返さgれたものに反映されていないことに気付きました. 変更を固定する方法はありますか?vgv

def f
  v = 5
  g = -> { v = 'Hello' }
  g.()
  v
end
f
# => 'Hello'

ご覧のとおり、への変更v 復帰後に「固着」しgます。

于 2013-08-03T01:08:49.057 に答える
8

Ruby ではメソッド内でメソッドを実際に定義するわけではありませんが、以下を使用できますlambda

def f
  v = 5

  g = lambda do
    v
  end

  g.call
end
于 2013-08-02T23:15:44.620 に答える
2

短い答え、いいえ。Ruby の関数には、Javascript の関数とは異なるスコープ規則があります。

より長い答えは、オブジェクトが定義されているスコープを保持する (クロージャと呼ばれる) Ruby でオブジェクトを定義できるということです。これらは、Ruby ではラムダ、Proc、およびブロックと呼ばれます。簡単な概要については、こちらをご覧ください。

編集: ブロックは Ruby オブジェクトではありませんが、オブジェクトである Proc に変換できます。

于 2013-08-02T23:20:40.320 に答える
1

クロージャーは、次の特徴を持つコードの名前付きブロック (一部の言語では関数、Ruby ではラムダまたはプロシージャ) です。

  • 別のスコープで呼び出された場合や、それらの変数が使用できなくなった場合 (スコープ外) であっても、定義されたスコープ (外側のスコープ) で使用可能なすべての変数の値を記憶しています。
  • オブジェです。したがって、変数に割り当てたり、渡したり、さまざまなスコープ内から呼び出したりすることができます。

以下は、Lambda を使用した例です。Proc を使用して同じことを行うことができます。

minutes = 40
def meditate minutes
    return lambda { minutes }
end

p = meditate minutes
minutes = nil
p.call

# Output:
=> 40

引数として数分かかる medicate メソッド内でラムダが作成されたことに注意してください。後でラムダを呼び出したとき、瞑想メソッドはすでになくなっていました。また、分の値を nil に設定します。それにもかかわらず、ラムダは「分」の値を記憶していました。

Ruby には、Lambda と Procs の 2 種類のクロージャーがあります。

メソッドはクロージャではなく、Method オブジェクトでもありません。Yukihiro Matsumoto (Matz) が彼の著書 The Ruby Programming Language で述べているように:

Method オブジェクトと Proc オブジェクトの重要な違いの 1 つは、Method オブジェクトがクロージャではないことです。Ruby のメソッドは完全に自己完結型であることを意図しており、スコープ外のローカル変数にアクセスすることはありません。したがって、Method オブジェクトによって保持される唯一のバインディングは、メソッドが呼び出されるオブジェクトである self の値です。

詳細については、Zen Ruby ブログのメソッドに関する投稿を参照してください。

于 2016-05-08T20:43:51.597 に答える