0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

yieldってやつがよくわからないので調べてみた

Last updated at Posted at 2023-05-01

yieldってやつがよくわからないので動かしてみた

基本形

def my_method
  p 'my_method called'
  res = 0
  yield res # <- ブロック変数に格納される
  p 'my_method done'
end

my_method do |res_from_yield|
  p 'in block'
  p res_from_yield # <- yieldに渡された値が入る
end

# 出力
# "my_method called"
# "in block"
# 0
# "my_method done"

実行順

  1. my_methodを呼ぶ
  2. my_method内、通常通り上から順番に実行される
  3. yield がいたらblock内の処理を実行する
    yield 値とするとblockに値を渡す
  4. blockの処理が終わったらmy_methodに帰ってくる

複数の引数を渡す

def my_method
  p 'my_method called'
  res  = "res"
  res2 = "res2"
  yield res, res2
  p 'my_method done'
end

my_method do |res, res2|
  p 'in block'
  p res, res2
end

# "my_method called"
# "in block"
# "res"
# "res2"
# "my_method done"

キーワード引数みたいのはハッシュにして渡すのがよさそう

def my_method
  yield({ message: "Hello, World!", count: 3 })
end

my_method do |options|
  puts "The message is: #{options[:message]}"
  puts "The count is: #{options[:count]}"
end

# The message is: Hello, World!
# The count is: 3

スコープは普通の関数と同じ

goのクロージャのような挙動ではないので、以下のコードは0, 1, 2...となるわけじゃない

def my_method
  res = res || 0
  yield res
  res += 1
end

3.times do
  my_method do |res_from_yield|
    p res_from_yield
  end
end

# 出力
# 0
# 0
# 0

当たり前だがインスタンス変数に置き換えてやればやりたいことはできる

def my_method
  @res = @res || 0 # <- インスタンス変数に置き換える
  yield @res
  @res += 1
end

3.times do
  my_method do |res_from_yield|
    p res_from_yield
  end
end

# 出力
# 0
# 1
# 2

用途を考えてみた

異なる種類のデータを同じ関数で柔軟に処理できる
やっぱり普通の関数でもよいきがしますね

def my_method(data)
  if data.is_a? Array
    data.each do |item|
      yield item
    end
  elsif data.is_a? Hash
    data.each do |key, value|
      yield key, value
    end
  else
    yield data
  end
end

# 配列を処理するブロックを渡す
my_method([1, 2, 3]) do |item|
  puts "item: #{item}"
end

# ハッシュを処理するブロックを渡す
my_method({ name: "Alice", age: 30 }) do |key, value|
  puts "#{key}: #{value}"
end

# 単一の値を処理するブロックを渡す
my_method("Hello, World!") do |data|
  puts data
end

感想

賢くないのでyieldは直感的に理解できなくて嫌いです
良い使い道があれば是非コメントしてください

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?