Rubyの単項演算子(+、-)の動作

あけましておめでとうございます。本年もTechRachoをよろしくお願いいたします。

年末年始はインフルエンザで完璧に寝正月になってしまったのですが、Rubyで小ネタを見つけたので記事にしてみました。
チェックにはRuby 2.5を使いました。

Rubyの単項演算子(+、-)の動作

基本の動作

今さらですが、単項のIntegerやFloatの前に付く+-はそのまま数学記号の正符号、負符号とみなせます。この場合+は何もしないと解釈されるため、最終的に数学記号の慣習に沿って+はドロップされます。

1     #=>  1
+1    #=>  1
-1    #=> -1
1.0   #=>  1.0
+1.0  #=>  1.0
-1.0  #=> -1.0

+-が複数ある場合、解釈後に圧縮されます。これは間にスペースがあっても同じです。

-+-- ++- -+ 1  #=> -1

2項演算でも同様です。

-1 -+-- ++- -+ 1 #=> -2

こんな書き方は誰もしませんが、数学記号としての正負符号の挙動が担保されていることがわかります。

この挙動は?

今回気づいたのは以下の挙動でした。

まず、丸かっこ()はあってもなくても単項演算子の解釈に違いはありません。

-(-1) #=>  1
+(-1) #=> -1

classメソッドでクラスを調べることもできます。

-1.class #=> Integer
+1.class #=> Integer

しかし、丸かっこの外に単項演算子がある状態でclassを取ってみると次のようになりました。

-(-1).class #=> NoMethodError: undefined method `-@' for Integer:Class
+(-1).class #=> NoMethodError: undefined method `+@' for Integer:Class

当初はおやっと思いましたが、(-1).classが先に解釈され、続いて戻り値Integerに対して単項演算子-が適用されたことにやっと気づきました。

この挙動を回避するには、丸かっこをさらに追加します。

(-(-1)).class #=> Integer
(+(-1)).class #=> Integer

これは変数などに対しても同様です。

a = 1
-a.class    #=> NoMethodError: undefined method `-@' for Integer:Class
(-a).class  #=> Integer

おまけ: 文字列結合の+

ついでながら、文字列結合演算子としての+も連続して置くことができます。

"a" + + "a" #=> "aa"

なお、文字列結合は原則として+ではなく式展開"#{}"を使いましょう。

Rubyでの文字列出力に「#+」ではなく式展開「#{}」を使うべき理由

関連記事

Ruby: ぼっち演算子`&.`の落とし穴(翻訳)

【保存版】Rubyスタイルガイド(日本語・解説付き)総もくじ

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

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ