ブロック
- それはクロージャ
- ブロックはメソッド呼び出し時のみ記述が可能
- ブロックはスコープを作る
def moko(a)
a + yield
end
moko(1) do
2 + 3
end
=> 6
moko(1) { 2 * 3 }
=> 7
# スコープを作る、とは?
# その正体は?クロージャ?
hage1 = 1
def moko
yield
end
moko do
hage1 = 100
hage2 = 100
end
hage1
=> 100
hage2
NameError: undefined local variable or method 'hage2'
ここ、重要そうな事が書いてあるぞ!
- (メソッド定義 && ブロック定義)外で定義されたhage1は、(メソッド定義 && ブロック定義)外から(当然)参照できる
- (メソッド定義 && ブロック定義)外で定義されたhage1は、ブロック定義内から参照できる。ブロックが生成された時の周りの変数等はクロージャに含められる(束縛される)
- ブロック定義中で定義されたhage2は、外側から参照できない。ていうかブロックと共に消滅する
- 上の例には書いていないが、メソッド定義外で定義されたhage1は、メソッド定義内から参照できない。ローカル変数の存在境界の1つはメソッド定義だから(このあたりややこしいよね)
- クロージャ、それは処理(ブロック)生成時の環境を束縛(環境への参照を保持)するもの
- Rubyではメソッド内から外部の変数は参照できないが、これを逆手に取れば呼び出し元の変数を処理に持ち込む数少ない手段ともなる
ブロックは引数を受け取れる
def moko(num)
yield(num, 2)
end
moko(1) do |a, b|
a + b
end
=> 3
メソッド内でブロックが指定されたかどうか判定
def moko(num)
return 'block...' if block_given? == false
yield(num, 2)
end
moko(1)
=> "block..."
moko(1) do |a, b|
a + b
end
=> 3
Proc
別ページへ移動しました Proc
lambda
こちらもチェック Proc#procクラス以外の手続きオブジェクト
- 「らむだ」と読む
- Procインスタンスを生成するがちょっと振る舞いが違う
- lambdaはメソッドぽい動き
- Proc(lambda)内でreturnした時に、lambdaはcallした行へ戻る(メソッドっぽい)、Proc(ブロック)はcallした所(生成元のスコープ)から脱出する
- 呼び出された時に、lambdaは引数の数を厳格に確認する(メソッドっぽい)、Proc(ブロック)は適当に無視するかnilで埋めてくれる
まずは普通にcallする、Procと特に違いは無いように見える
lmd = lambda { |a| p a }
# 1.9からの新記法
lmd = -> (a) { p a }
lmd.call(1)
1
=> 1
return時の振る舞いがProcと違う
# Proc
def moko
proc = Proc.new do
return 1
end
proc.call # returnで現在のスコープを脱出する この行にreturnが書いていたかのような動作
2 # この行は実行されない
end
moko
#=> 1
# lambda
def moko
lmd = -> do
return 1
end
lmd.call # returnで脱出するのはProc(lambda)内の処理だけ
2 # この行は実行される
end
moko
#=> 2
当然ながら、トップレベルでProc { return }すると戻り先が無いのでエラー
Proc.new { return }.call
LocalJumpError: unexpected return
# うう・・この動作はどう説明すればいい・・
def moko
yield
end
moko do
return
end
LocalJumpError: unexpected return