ブロック
ブロックとは
- do~endまたは{~}で囲われた引数となるためのもの
- それ単体では存在できず、メソッドの引数にしかなれない
- 引数として渡されたブロックは、yieldによって実行される
1
2
3
4
5
6
7
8
| def my_method
yield
end
my_method do
p "Hello, block!"
end
=> "Hello, block!"
|
説明
1
2
3
4
5
6
7
8
| def my_method(&block)
block.call
end
my_method do
p "Hello, block!"
end
=> "Hello, block!"
|
1
2
3
4
5
6
7
8
9
| #メソッド定義
def my_method(&block)
yield
end
my_method do
p "Hello, block!"
end
=> "Hello, block!"
|
さらに、
yield
を使うなら引数の(&block)
はいらないので
1
2
3
4
5
6
7
8
| def my_method
yield
end
my_method do
p "Hello, block!"
end
=> "Hello, block!"
|
こういうふうに省略できる。
Proc
- ブロックをオブジェクト化したものがProc
- Procオブジェクトはcallで呼び出すことが出来る
- Procに引数を持つこともできる
- Proc.newとlambdaはほぼ同義
Procオブジェクトの定義と呼び出し
1
2
3
4
5
6
| proc = Proc.new do
p "hoge"
end
proc.call
=> "hoge"
|
Procに引数が渡された場合
1
2
3
4
5
6
| proc = Proc.new do |s|
p "Hello, #{s}!"
end
proc.call("Proc")
=> "Hello, Proc!"
|
Proc.newとlambdaはほぼ同義
1
2
3
4
5
6
7
| lambda1 = lambda { p "hoge" }
lambda1.call
=> "hoge"
lambda2 = lambda { |s| p "Hello, #{s}!" }
lambda2.call("Proc")
=> "Hello, Proc!"
|
Procとlambdaの違い
- lambdaはブロックの引数の数が違うとエラーを起こしてくれる。
1
2
3
4
5
6
7
8
9
| proc = Proc.new { |a,b,c| p "#{a},#{b},#{c}" }
proc.call(2, 4)
=> 2,4,nil
lambda1 = lambda { |a,b,c| p "#{a},#{b},#{c}" }
lambda1.call(2, 4)
=> wrong number of arguments (2 for 3) (ArgumentError)
|
- 明示的にreturnやbreakを行った場合の挙動が違います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| def method_proc
proc = Proc.new { return p "proc"}
proc.call
p "method_proc"
end
method_proc
=>"proc"
def method_lambda
lambda = lambda{ return p "lambda"}
lambda.call
p "method_lambda"
end
method_lambda
=>"lambda"
"method_lambda"
|
ブロックやProcのメリット
柔軟に拡張できる
下のコードのようにメソッドを汎用的に使うことができる
1
2
3
| def my_method(input, someProc)
someProc.call(5, input)
end
|
1
2
3
4
5
6
| sum_proc = Proc.new do |x, y|
p x + y
end
my_method(3, sum_proc)
=> 8
|
1
2
3
4
5
6
| string_proc = Proc.new do |x, string|
p string * x
end
my_method('hello_proc! ', string_proc)
=> "hello_proc! hello_proc! hello_proc! hello_proc! hello_proc! "
|
クロージャとしての機能が得られる
サンプル①
1
2
3
4
5
6
7
8
9
| def bar
str = 'bye'
yield('Jo')
end
str = 'hello'
bar { |name| "#{str}, #{name}" }
=> "hello, Jo"
|
サンプル②
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| n = 1
def foo(n)
n = n + 1
end
foo(n)
=> 2
foo(n)
=> 2
foo(n)
=> 2
foo(n)
=> 2
|
1
2
3
4
5
6
7
8
9
10
11
| n = 1
proc = Proc.new do
n = n + 1
end
proc.call
=> 2
proc.call
=> 3
proc.call
=> 4
|
block_given?
block_given?とは
引数としてブロックが与えられたかどうかを判別するメソッド。
使い方
1
2
3
4
5
6
7
| def greet_method
if block_given?
yield('hello!')
else
p "ブロックがありません。"
end
end
|
1
2
3
4
| greet_method do |str|
p str
end
=> "hello!"
|
1
2
| greet_method
=> "ブロックがありません。"
|
参考
https://qiita.com/kidach1/items/15cfee9ec66804c3afd2
https://qiita.com/ryo-ma/items/24c46592b45775e8644d