電子書籍の厳選無料作品が豊富!

rubyでのproc

http://d.hatena.ne.jp/shunsuk/20090101/1230816826

ここのサイトで解説されていることなんですけど,

「同じblockを何度も使いたいときがあります。そんなときに再利用するためのコードがProcです。blockとProcの唯一の違いは、blockは保存できないということです。Procについて見てみましょう。」

とあるのですが,なにをもってblockは保存できないといってるのでしょうか?

「lambdaはメソッドと同じように振る舞いますから、returnを使うことができます。この意味の違いは、下の例に現れます。」

の下にサンプルプログラムがあると思いますが,


puts generic_return(Proc.new { |x, y| x + 2; y + 2 })

puts generic_return(Proc.new { |x, y| [x + 2, y + 2] })

この2行ではエラー処理が行われず,なんらかの出力がされています,

これはなぜでしょうか?メソッドの中にreturnがある限りエラー処理が起こると思っているのですが・・・

あと,あまり関係ない質問になるかもしれませんが

array.iterate!(method(:square))

このような記述のとき,squareは関数名ということはわかるのですが,

:(コロン)これはなにを指すのでしょうか?

よろしくおねがいします.

A 回答 (4件)

> なにをもってblockは保存できないといってるのでしょうか?



Lambdaの項の最初に“Procを2通りの方法で使ってきました。直接渡す方法と、変数に保存する方法です。”という記述があります。
保存とは変数に保存するということの様です。Procのインスタンスは変数に保存して使い回しができますが、ブロックはできないということではないでしょうか。


> この2行ではエラー処理が行われず,なんらかの出力がされています,
> これはなぜでしょうか?メソッドの中にreturnがある限りエラー処理が起こると思っているのですが・・・

メソッドの中ではなくて、Proc.new{ }の中にreturnがある場合ですね。
この中にreturnがあると、そのProcが定義されたレベルからのreturnを行おうとするようです、このサンプルだとProcはプログラムのトップレベルで定義されているので、トップレベルからreturnしようとしてエラーになっている様です。
要するにProcを使用する場合はreturnを使うな、returnを使う場合はlambdaを使えということではないでしょうか。
    • good
    • 0

はまりやすいところですが、proc組み込み関数はくせ者です。


Ruby1.8ではproc組み込み関数は、lambdaを返します。

Proc.new{。。。。} # => procオブジェクト
lambda {。。。。} # => lambdaオブジェクト(クラスはProc)
proc {。。。。} # => lambdaオブジェクト(クラスはProc)!!!!!注意

Ruby1.9ではproc組み込み関数の機能が変更されています。

Proc.new{。。。。} # => procオブジェクト
lambda {。。。。} # => lambdaオブジェクト(クラスはProc)
proc {。。。。} # => procオブジェクト

#3の方は、Ruby1.9をお使いと思われます。
    • good
    • 0

#解説は他の方に任せてサンプルのみ。




#ブロックを返す単純なメソッドを定義
def make_proc1(&b)
b
end
#別の例
def make_proc2
proc
end

#ブロック保存もどきが作れる。
p= make_proc1{puts "proc test"}
p.call
p= make_proc2{puts "proc test"}
p.call

#が以下のように直接は保存できない。(blockは保存できないにあたる?)
p = {puts "proc test"}




return #トップレベルのreturn(※1)は戻り先が無いのでLocalJumpError

p = proc{ p "proc test";return}#トップレベルのreturn(※1)を含むproc作成。

p.call #これもップレベルのreturn(※1)と一緒LocalJumpError

def proc_test
return #メソッド内のreturn(※2)。nilを返してproc_testを終了する。
p "fin proc_test" #これは実行されない。
end

def proc_test
p = proc{ p "proc test";return}#proc_testのreturn(※2)と一緒。
p.call #proc_testのreturn(※2)と一緒なのでLocalJumpErrorはおきない。
p "fin proc_test" #これは実行されない。
end



def proc_test(b)
b.call #トップレベルのreturn(※1)を含むprocの場合、戻り先が無いのでLocalJumpError
p "fin proc_test" #これは実行されない。
end
proc_test(proc{ p "proc test";return})#トップレベルでreturn(※1)を含むprocを渡す。


def sub_proc
#sub_procからのreturnだが、呼び出す際にはsub_procは
#すでに終了しているのでエラー。
proc{ p "proc test";return}
end
proc_test sub_proc

この回答への補足

#!/usr/bin/ruby

p = proc{ p "proc test";return}#トップレベルのreturn(※1)を含むproc作成。
p.call #これもップレベルのreturn(※1)と一緒LocalJumpError

これを実行したところ,

"proc test"

と出力されました.

#!/usr/bin/ruby

def proc_test
p = proc{ p "proc test";return}#proc_testのreturn(※2)と一緒。
p.call #proc_testのreturn(※2)と一緒なのでLocalJumpErrorはおきない。
p "fin proc_test" #これは実行されない。
end

としたところ,proc testが出力されそうですが,なにも出力されませんでした.

#!/usr/bin/ruby

p = proc{ p "proc test";return}#トップレベルのreturn(※1)を含むproc作成。
p.call #これもップレベルのreturn(※1)と一緒LocalJumpError

これを実行したところ,

"proc test"

と出力されました.

#!/usr/bin/ruby

def proc_test(b)
b.call #トップレベルのreturn(※1)を含むprocの場合、戻り先が無いのでLocalJumpError
p "fin proc_test" #これは実行されない。
end
proc_test(proc{ p "proc test";return})#トップレベルでreturn(※1)を含むprocを渡す。

これを実行したところ,

"proc test"
"fin proc_test"

と出力されました.


#!/usr/bin/ruby

def proc_test(b)
b.call #トップレベルのreturn(※1)を含むprocの場合、戻り先が無いのでLocalJumpError
p "fin proc_test" #これは実行されない。
end

def sub_proc
#sub_procからのreturnだが、呼び出す際にはsub_procは
#すでに終了しているのでエラー。
proc{ p "proc test";return}
end

proc_test sub_proc

これを実行したところ,

"proc test"
"fin proc_test"

と出力されました.

LocalJumpErrorrubyのバージョンにもよるのでしょうか?特にエラーは出力されませんでした.

ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]

また,実行時には

ruby -W test.rb

と警告をつけて実行しています.

補足日時:2010/08/01 00:13
    • good
    • 0

>なにをもってblockは保存できないといってるのでしょうか?




原文は見てませんが、翻訳を見る限り、この文脈で「保存」とはどういう意味なのか定義されてません。従って意味不明の文章です。
あえて想像すると、「変数に直接代入できない」という意味ではないでしょうか。別の所に書いてありますが、呼び出され側のメソッドで、&が付いた仮引数で受け取ることは出来るので、変数には代入できるのですが、直接ではありません。
a = {|x| x*2}
ということは出来ないので。

>これはなぜでしょうか?メソッドの中にreturnがある限りエラー処理が起こると思っているのですが・・・

何故かと問われても、「正しいプログラムだから」としか言いようがないです。逆に何故「エラー処理が起こる」と思ったのでしょうか?

>このような記述のとき,squareは関数名ということはわかるのですが,:(コロン)これはなにを指すのでしょうか?

単に square と書くと、square というメソッドを呼び出してその結果を表します。

ここでは、呼び出さずにメソッドの名前を伝えたいわけです。:square はシンボルというもので、簡単には説明できませんので、理解できるまでは『「書き換えられず部分取り出しも出来ない文字列」のようなもの』と思っておけば良いです。実際、
array.iterate!(method("square"))
と書いても同じ結果です。文字列よりシンボルの方が処理効率が良く、またシンボルしか書けないところもあります。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!