11
12

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 5 years have passed since last update.

do ~ endと { ~ }の結びつきの違いについて

Last updated at Posted at 2014-06-18

タイトルでネタバレしつつある気がしますが、唐突に問題を出してみます。

sample1.rb
data = {'hoge' => false}
p data.any? do |key, val|
  val
end

この結果は何が出力されるでしょう?
any?といえば、レシーバの要素が全てfalseyのときだけfalse、1つでもtruthyの要素があればtrueを返すEnumerableのメソッドです。

false、と答えた人はたぶん
「valがfalseなんだから、そりゃfalseだろ」って認識だと思います。

trueと答えた人は
「そんな聞き方するってことはtrueだろ」って人と
ちゃんと理由が分かる人の二種類がいると思います。
後輩に訊ねたところ、前者の答えが返ってきていささか面白くなくてぷんすこです。

結果は当然流れ的にtrue。

はて、ここで何が起きているのか?
ここで掲題の話になるわけです。

公式ドキュメントにはこうあります。

{ ... } の方が do ... end ブロックよりも強く結合します
Ruby 2.1.0 リファレンスマニュアル

つまり

sample1.rb
data = {'hoge' => false}
p(data.any?) do |key, val|
  val
end
# => true

こうなっちゃってたわけですね。
data.any?にはブロックを渡しておらず、dataの要素が全部偽であることのチェックをした結果を出力していたわけです。
またdataはHashなので、空Hashでもない限りは要素を持っている=trueとなりますので、こういった結果になっていたわけです。

ここでdo ... endではなく{ ... }を使用している場合は想定通りの結果になります。

sample2.rb
data = {'hoge' => false}
p data.any? { |key, val|
  val
}
# => false

また、pがブロックを受けてゴニョゴニョするようなメソッドだったらまた違った結果になっていたことでしょう。

do ... end{ ... }の結びつきの違いの話は非常に有名ですが、初心者ですと違いが分からずに同じようにハマるかもしれないのでここに共有しておきます。

私の場合も独自のコーディングルールで

ワンライナー(1行)で記述する際は { ... }を使い、
ワンライナーで可読性が落ちる場合には do ... end で複数行で記述しましょう。

というものがありまして、それを守りつつany?の挙動を確認しているときに引っかかってしまいました。

11
12
2

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
11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?