ごとけんです
In message "[ruby-list:19246] 破壊的イテレータ?"
on 99/12/08, Hiroshi Saito <HiroshiSaito / pob.org> writes:
>a.itr do |i|
> i += 10
> print i, ","
>end
i += 10 は i = i+10 なので、i という変数が何を指すかを変えて
いることになります。絵で描くと以下のような感じ:
ブロックの実行を始めたところ:
a = [1, 2, 3, 4, 5]
↑
i
i += 10 を実行した後:
a = [1, 2, 3, 4, 5]
i→11
>つまり、イテレータのブロックでの結果をイテレータ本体に
>持ち越すことはできますか?
Rubyの変数はオブジェクトを指すだけのもので、変数に対する操作
は代入(指すものを変えること)と参照しかないので、
(1) 添字を使ったイテレータにして、添字で指定したコンテナの
位置に代入させるか
(2) 参照しているオブジェクトを変化させる方法をつかうか
のいずれかできます。
# (1) の例
h = {:foo => 0, :bar => 1, :baz => 2}
h.each_key{|key|
h[key] += 10 # Hash#[]= の呼出し
}
p [h[:foo], h[:bar], h[:baz]] #=> [10, 11, 12]
a = [0,1,2]
a.each_with_index{|e,i|
a[i] = e + 10 # Array#[]= の呼出し
}
p a #=> [10, 11, 12]
# (2) の例
a = [[0],[1],[2]]
a.each{|i|
i[0] += 10 # 各要素iへの Array#[]= の呼出し
}
p a #=> [[10], [11], [12]]
また Array#filter は評価した結果で要素を置き換えるものです。
a = [0,1,2]
a.filter{|i| i+10}
p a #=> [10, 11, 12]
ユーザ定義する場合はこれらのいずれかを用意する必要があります。
-- gotoken