Rubyの否定演算子2つ重ね「!!」(double-bang)でtrue/falseを返す

こんにちは、hachi8833です。

Rubyの否定演算子「!」を2つ重ねた「!!」を使ってメソッドの戻り値をtrue/falseに揃える方法を知ったのでメモします。以下、便宜上「二重感嘆符」と表記します。

対象

  • Ruby: 2.3.1
  • Rails: 5.1.0.alpha

core_ext/regexp.rbの二重感嘆符「!!

Active Supportをたどっていて、Rails 5.1.0.alphaのcore_ext/regexp.rbで以下のコードを見つけたのがきっかけでした。

def match?(string, pos = 0)
  !!match(string, pos)
end unless //.respond_to?(:match?)

気になったのは二重の感嘆符「!!」です。

!!match(string, pos)で呼び出しているRegexp#matchはRubyのコアメソッドで、マッチしない場合にnilを返します。

Rubyでは、truefalseのどちらか(論理値)だけを返すメソッド名の末尾にはmatch?のように疑問符を追加する慣習があります。

この二重感嘆符「!!」を使うと、nilを返すmatchメソッドを簡単にmatch?のように論理値メソッド化できます。

!!」の動作: すべてをtruefalseにする

ご存じのとおり、Rubyではnilfalse以外のオブジェクトはすべてtrueとして扱われます。そして否定の論理演算子「!」はtruefalseを反転します。

  • !nil #=> true
  • !!nil #=> false
  • !false #=> true
  • !!false #=> false
  • !!その他何でも #=> true

反転の反転は論理上何も変化をもたらしませんが、表現がtruefalseに揃えられるところがポイントです。

!!」を試してみる

Ruby 2.3.1で「!!」の動作を実際に確認してみます(注: Rails環境ではありません)。

" "で囲んだ文字列リテラルはさすがにwarningが表示されましたが、試した範囲ではいずれも論理値オブジェクトtruefalseに変換されました。

Ruby 2.3.1にRegexp#match?を導入してみる

!!」の動作を確認できたので、続けて先ほどの#match?を試しにRuby 2.3.1に導入してみましょう。

class Regexp
  def match?(string, pos = 0)
    !!match(string, pos)
  end
end

簡単のため、元のコードの末尾にあったunless //.respond_to?(:match?)は省略しています。

#match?が最小限の簡潔なコードで論理値を返すようになりました。if文を使わずに書けるところがキモチイイですね。

追記: core_ext/regexp.rbの#matchについて

core_ext/regexp.rb#match?メソッドは、2.4より前のRubyで#matchメソッドとの互換性を取るために、Ruby 2.4の登場に先がけて今年の夏頃masterに追加されたようです。

masterは5.1.0.alphaにつき、今後さらに変更される可能性がありますのでご了承ください。

Defines Regexp.match? for Ruby versions prior to 2.4. The predicate has the same interface, but it does not have the performance boost. It’s purpose is to be able to write 2.4 compatible code.

Xavier Noria
5.1.0.alpha の Active Support: CHANGELOG.mdより

追記: 感嘆符の呼び方について

感嘆符!」は日本語だとビックリマークとエクスクラメーションマークと書かれたりしますが、英語圏のプログラミング関連では「bang」と表記されることが多いようです。正式なexclamation markだと長ったらしいからでしょう。

二重感嘆符「!!」ならdouble-bangbang-bangなどと書かれることが多いので、ググる場合に参考にしてください。

Rubyでは値を変更する破壊的メソッド名の末尾に「!」を付ける慣習がありますが、これも英語圏ではbang methodと呼ばれることがよくあります。

おまけ

参考

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833 コボラー、ITコンサル、ローカライズ業界を経てなぜかWeb開発者志願。 これまでにRuby on Rails チュートリアルの大半、Railsガイドのほぼすべてを翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

Rubyスタイルガイドを読む

BigBinary記事より

ActiveSupport探訪シリーズ