0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ruby 破壊の話②メソッド編

Last updated at Posted at 2020-02-21

前回の内容を簡単にまとめると、

  • =で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++という表現を許すわけにはいかなかったのだ。
とても理にかなっていて美しいなと思った。

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?