7

Rubyでクロージャを書こうとしています。これは Python で書かれたコードです:

def counter():
    x = 0
    def increment(y):
        nonlocal x
        x += y
        print(x)
    return increment

インクリメント内から変数 x にアクセスして変更できるように、Ruby に「非ローカル」に相当するものはありますか?

4

3 に答える 3

2

たぶん次のようなものです:

class CGroup
  def counter
    @x ||= 0
    lambda do |y|
      @x += y
    end
  end
end

それで:

group = CGroup.new
c = group.counter
c.call(1)
=> 1
c.call(1)
=> 2

Python のnonlocal.

EDIT : インスタンス変数は不要であり、メソッドのローカル変数を使用して同じことを実現できます。これにより、クラスは不要になりますが、Ruby では多くのことがオブジェクトのコンテキスト内で行われます。

于 2012-12-09T01:58:38.210 に答える
2

オブジェクトを使用することに異論があるのに、なぜラムダを使用しないのでしょうか?

counter_generator = ->(){
  x ||= 0
  ->(y){
    x += y
    puts x
  }
}

i = counter_generator.call
=> #<Proc:0x00000100867508@(irb):17 (lambda)>
i.call(1)
1
=> nil
i.call(1)
2
=> nil

x の値を返すのではなく、出力するように指定しただけなので、インクリメンタは実際には nil を返すことに注意してください。

于 2012-12-09T02:15:26.987 に答える
2

nonlocalキーワードは、キャプチャする変数を Python に指示します。Ruby では、そのようなキーワードは必要ありません。特に明記しない限り、すべての変数がキャプチャされます。

したがって、Python コードに相当する Ruby は、ほぼそのまま変換されます。

counter = -> {
  x = 0
  ->y {
    x += y
    puts x
  }
}

i = counter.()

i.(2)
# 2

i.(3)
# 5

ただし、メソッド for を使用する方がおそらくより慣用的counterです。

def counter
  x = 0
  ->y {
    x += y
    puts x
  }
end

i = counter

i.(2)
# 2

i.(3)
# 5
于 2012-12-09T02:39:08.080 に答える