Rails

Rubyで「+ 1」と「+1」が違うとき

ただのタイポによるエラーだったのだけど、「なんでArgumentError?」と考えてみたら面白かったのでメモ。

# Hogeクラスをつくって

class Hoge
attr_accessor :count
end
hoge = Hoge.new

# hoge.countに値を入れる
hoge.count = 1
p hoge.count
# => 1

# hoge.countを1増やす
hoge.count = hoge.count + 1
p hoge.count
# => 2

# hoge.countをもう1増やそうと思うと
hoge.count = hoge.count +1
# => 3になる、と思いきやエラーになる
# ArgumentError:
# wrong number of arguments (given 1, expected 0)

なぜかというと、1のコードは2のコードと同じ。

# 1

class Hoge
attr_accessor :count
end

# 2
class Hoge
def count
@count
end

def count=(count)
@count = count
end
end

Rubyの場合、メソッドの引数は()に入れて渡すのだけれど、省略可能になっている。

hoge.count + 1

# => これはgetterのcountメソッドにアクセスして、その返り値に +1している
# 評価順はこう
# (hoge.count) + 1

hoge.count +1

# => この場合+1がgetterの引数になっている
# 評価順はこう
# hoge.count(+1)

+1の(スペースが間に入らない)場合、呼び出されるのはgetterのcountで、

getterは引数を取るよう定義されていないのでArgumentErrorが発生する。

だから、こうすれば通るけど、jsでよくかかれるような+=とは違う結果になる。

hoge.count = 1

hoge.count = +1
# => 1
# +1されて2が返るのではなく、何度やっても1が返る
hoge.count = +1
# => 1