あけましておめでとうございます。本年も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"
なお、文字列結合は原則として+
ではなく式展開"#{}"
を使いましょう。