質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

4212閲覧

deleteでなぜ破壊的変更になるかわからない

yoshida10

総合スコア14

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2018/09/16 00:12

プログラミング初心者です。
今「プロを目指す人のためのRuby入門」という本で勉強をしています。
本ではirbでの実行結果が#=>の後のコードに記載されています。
以下が本に記載されていたコードです。

class Product SOME_ NAMES = ['Foo', 'Bar', 'Baz'] def self.names_without_foo( names = SOME_NAMES) # names が デフォルト 値 だ と、 以下 の コード は 定数 の SOME_NAMES を 破壊的 に 変更 し て いる こと に なる names.delete('Foo') names end end Product.names_without_foo #=> ["Bar", "Baz"] # 定数 の 中身 が 変わっ て しまっ た! Product::SOME_NAMES #=> ["Bar", "Baz"]

上記の「 names が デフォルト 値 だ と、 以下 の コード は 定数 の SOME_NAMES を 破壊的 に 変更 し て いる こと に なる 」という文章が理解できません。
何故delete!としていないのに定数の中身を破壊的に変更できるのでしょうか?

ちなみに、以下のコードを実行したところ、deleteでは定数を破壊的に変更できず、delete!では変更可能でした。#=>の後には実行結果を記載しています。

Ruby

1TEISUU = 'こんにちは' 2puts TEISUU #=> こんにちは 3puts TEISUU.delete('に') #=>こんちは 4puts TEISUU #=> こんにちは 5puts TEISUU.delete!('に') #=>こんちは 6puts TEISUU #=>こんちは 7

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

著者の伊藤です。すでに解決済みなので回答が重複する部分もありますが、回答しておきます。

何故delete!としていないのに定数の中身を破壊的に変更できるのでしょうか?

Rubyを学び始めたばかりの方はよく勘違いされるのですが、「!で終わる = 破壊的メソッド」ではありません。
2.11.3項にも書いたとおり、!で終わるメソッドは「使用する際に注意が必要」という意味です。

さらに、破壊的メソッドがすべて!で終わるとも限りません(同じく2.11.3項参照)。

もう一点付け加えると、「"!ありメソッド"がある場合は、"!なしメソッド"も定義しておく」という慣習もあるようです(これは「プロを目指す人のためのRuby入門」には書いていません)。

以下のコードを実行したところ、deleteでは定数を破壊的に変更できず、delete!では変更可能でした

APIドキュメントを見てもらえればわかると思いますが、Stringクラスにはdeletedelete!の2種類がありますが、Arrayクラスにはdeleteメソッドしかありません。

https://docs.ruby-lang.org/ja/latest/class/String.html
https://docs.ruby-lang.org/ja/latest/class/Array.html

そして、StringクラスとArrayクラスは互いに無関係なクラスなので、たまたまdeleteという同じ名前のメソッドが定義されているだけです。

上記の議論を総合すると、「(Arrayクラスでは)何故delete!としていないのに定数の中身を破壊的に変更できるのでしょうか?」という問いに対しては、次のような回答が導出されます。

  • !が付いているからといって破壊的メソッドとは限らない
  • !が付いていないからといって非破壊的メソッドとは限らない
  • !ありのメソッドが定義されている場合は、!なしの同名メソッドも定義した方がよい
  • Arrayクラスには(Stringクラスと異なり)delete系のメソッドが1種類しか定義されていない
  • 結果として、Arrayクラスには「破壊的なdeleteメソッド(!なしの破壊的メソッド)」のみが定義された

とはいえ、このあたりの議論は、クラスライブラリの設計の話になります。
僕は自らの経験に基づいて上のような説明をしましたが、実際のところ(本当のいきさつ)はまつもとさん(Matz)や、コミッタのみなさんしかわからないと思います。

本当の真相を知りたい場合は、まつもとさんに「ねえ、どうして!?」と突撃インタビューするのが一番確実だと思います(笑)。

投稿2018/09/18 08:39

編集2018/09/18 10:20
jnchito

総合スコア357

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoshida10

2018/09/19 23:44

わかりやすい回答ありがとうございます! クラスごとに同名で異なる働きをするメソッドが定義されてることもあるということが知らなかったので、大変参考になりました!
guest

0

ベストアンサー

何故delete!としていないのに定数の中身を破壊的に変更できるのでしょうか?

よく誤解されますが、「破壊的なメソッドには必ず!がついている」訳ではありません

ただ、ArrayとStringで動作が違うというのもあまりすっきりはしない感じですね。

投稿2018/09/16 00:37

編集2018/09/16 00:39
maisumakun

総合スコア145366

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoshida10

2018/09/16 01:41

非常にわかりやすい回答ありがとうございます ArrayクラスとStringクラスに異なるdeleteが定義されていたのは知らなかったので参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問