

Rubyの配列において，配列の要素を範囲指定して削除したいです．  
以下のURLを参考にしても全く同じ結果にはならないです．  
<https://uxmilk.jp/24060>

Rubyのバージョンは`ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin16]`です．

[code]

    target = [1, 2, 3, 4, 5, 6, 7]
    aaa = target.slice!(1, 3)
    p aaa
    
    
    a = ["a", "b", "c", "d", "e"]
    p a.slice!(1, 3)
    
[/code]

上記の実行結果は以下になります．

[code]

    [2, 3, 4]  # => [1, 5, 6, 7]にならない
    ["b", "c", "d"]  # => ["a", "e"]にならない
    
[/code]

期待した動作をしなく，原因がわかりません．  
期待した動作をするようにするにはどのようにしたら良いでしょうか．  
ご教授宜しくお願いします．


CC BY-SA 4.0
2019-09-27T10:59:52.470
59324
2019-09-29T05:03:42.327
2019-09-27T11:30:00.047
30173
30173
question
ruby
配列の要素を範囲指定で削除したいけどできない


`slice(1, 3)` のようにコールすると、第一引数のインデックスから第二引数の文字数の部分文字列を返します。  
つまり、 `1, 3` の場合は2(0始まりなので1+1)文字目から3文字を取り出すことになります。  
<https://docs.ruby-lang.org/ja/latest/class/Array.html#I_SLICE>

`slice!(1, 3)` のようにコールすると、第一引数のインデックスから第二引数の文字数の部分文字列をレシーバーから削除します。  
そして、戻り値は `slice` と違ってレシーバー(削除済みの配列)ではなく、削除した要素が返されます。  
<https://docs.ruby-lang.org/ja/latest/class/Array.html#I_SLICE--21>

つまり、そちらのコードの目的は `a.slice!(1, 3)` で達成されていて、返り値は気にせずに  
再度 `a` にアクセスすると `['a', 'e']` が出来上がっています。


CC BY-SA 4.0
2019-09-27T11:36:57.767
59325
2019-09-29T05:03:42.327
2019-09-29T05:03:42.327
5793
29695
59324
answer


Rubyの標準ライブラリのメソッドには

  * レシーバのオブジェクトのコピーに何らかの操作を加えた結果を返すもの
  * レシーバのオブジェクト自体を変更するもの

があり、前者を「非破壊的」メソッド、後者を「破壊的」メソッドと言います。同様の処理をする非破壊的メソッドと破壊的メソッドがある場合、破壊的メソッドの方のメソッド名に"!"をつけるのが慣習となっています。

(あくまで同機能のメソッドがある場合でしかも慣習なので、一般的に「"!"がついていれば破壊的メソッド」ではないことに注意してください)

`slice`/`slice!`もこのパターンで、前者は配列をスライスした結果を返し(元のオブジェクトはそのまま)、後者は呼び出したオブジェクト自体を変更します。

破壊的メソッドの戻り値が何になるかはメソッド次第なので注意が必要です。`slice!`は削除した要素を返すのですが、「処理が行われれば`self`、行わなければ`niL`」を返すものもあります。

例えば

[code]

    str2 = str.sub(/hoge/, 'fuga') 
    #以後str2を操作してstrは触らない
    
[/code]

こういうコードで誤って`sub!`を使ったとすると、変換が行われればどちらも同じ動きをしますが、変換が行われないと`str2`は`str`のコピーが入っているつもりが実際には`nil`になります。変換がまれにしか行われない場合、これはかなりわかりにくいバグになります。

なので、非破壊的メソッドと破壊的メソッドの使い分けには十分注意してください。


CC BY-SA 4.0
2019-09-29T01:26:00.263
59335
2019-09-29T04:59:43.887
2019-09-29T04:59:43.887
5793
5793
59324
answer