前回の内容を簡単にまとめると、
- =でidが変わる。(=はidを変える働きがある)
- idが変わることにより結果的に参照する値も変わる。
今回は=を使わなくても参照先の値が変わってしまう例を見ていく。
ruby 破壊の話シリーズ |
---|
ruby 破壊の話①「=」のふるまい |
ruby 破壊の話②メソッド編 |
ruby 破壊の話③関数編 |
ruby 破壊の話④破壊的なメソッド編 |
ruby 破壊の話⑤dup編 |
破壊的メソッド
mutableの例
=なしでidは変えられない。
idを変えずに参照先が変わってしまうというのはすなわち、そもそもidが対応している値自体が変わってしまう事象を指す。
こういったメソッドを破壊的メソッドと呼び、"!"が付いているのが特徴である。
irb(main):001:0> a='abc' #aを文字列abcを指すよう設定する
=> "abc"
irb(main):002:0> a.__id__ #aのidを確認しておく
=> 47064986806140
irb(main):003:0> a.reverse #reverseは元の文字列を逆さにする普通のメソッド
=> "cba"
irb(main):004:0> a #aの値自体は変わらない
=> "abc"
irb(main):005:0> a.__id__ #もちろんidも変わらない
=> 47064986806140
irb(main):006:0> a=a.reverse #左辺aを右辺aの逆さ文字列を参照するように設定
=> "cba"
irb(main):007:0> a.__id__ #=で異なるものを設定しなおしているのでidも変更される
=> 47064986914720
irb(main):008:0> a.reverse! #reverse!は元の文字列を逆さにし、上書きしてしまう破壊的メソッド
=> "abc"
irb(main):009:0> a #006で設定した値と異なる
=> "abc"
irb(main):010:0> a.__id__ #しかしidは007で確認したものと同じ
=> 47064986914720
このように、idを変えずidが指す値自体を変更するのが破壊的メソッドである。
値が変わってしまう危険性があるので、自分で破壊的なメソッドを作る場合にも!を付けることが推奨される。
ただしここで言う破壊的なメソッドとは、reverse!などの破壊的メソッドとは少し性質が異なる。
そのため私は、「破壊的メソッド」とはあらかじめ用意されているreverse!やsort!などを指すこととし、自作した破壊的なメソッドのことは「破壊的"な"メソッド」と呼ぶようにしている。
immutableの例
immuttableの例というより、そもそもimmutableとは不変という意味で、破壊することは不可能である。
以下で、シンボルがimmutableであることがわかる。
irb(main):001:0> a=:abc #aをシンボルabcに設定
=> :abc
irb(main):002:0> a.reverse #reverseは文字列のメソッドなので
NoMethodError: undefined method `reverse' for :abc:Symbol
from (irb):2
from /usr/local/rbenv/versions/2.4.2/bin/irb:11:in `<main>'
irb(main):003:0> a.reverse! #もちろん破壊できない
NoMethodError: undefined method `reverse!' for :abc:Symbol
from (irb):3
from /usr/local/rbenv/versions/2.4.2/bin/irb:11:in `<main>'
irb(main):004:0> a #シンボルは不変
=> :abc
irb(main):005:0> a.__id__ #idを確認
=> 1162268
irb(main):006:0> a.to_s.reverse! #to_sを使って破壊しようとすると表示は成功
=> "cba"
irb(main):007:0> a.__id__ #to_sは破壊的メソッドではないのでa自体は無傷
=> 1162268
irb(main):008:0>
まとめ
破壊的メソッドは、idに紐付けられる値自体を変更する。
続きは次の記事で
余談 rubyで i++ が出来ない話
統計を取ったわけではないが、i=i+1やi+=iの意味で、i++という記法が使えない言語は少ないのではないだろうか。
rubyは使えないようで、最初ちょっと驚いた。
c出身ということもあり、まあcの方がもっと全然実装されてないことあるわって思って気にせずi=i+1と書いていたが、rubyについて理解を深めると、納得の理由だった。
理由は数字がimmutableであることと=のふるまいで説明できる。
例1
i=1
i++
p i
2が表示されてほしいところだが、=に注目してよくよく考えると、これで2が表示されるわけがない。
=はこのコードに一つ。最初の行だけ。1はimuttable
なのでiは1と同じidということ。その後には=が無いので、最後までiは1と同じidである。
これが2を指しているわけがない。
例2
i=1
i=i+1
p i
同じようでもこれは2になる。
なぜなら2行目でiのidを変更しているからだ。
まとめると、数字をimmutableに設定し、=なしではidを変えられない言語仕様上、i++という表現を許すわけにはいかなかったのだ。
とても理にかなっていて美しいなと思った。