2014-01-07 8 views
7

Я не мог понять, почему в Ruby Array#slice и Array#slice! ведут себя не так, как Array#sort и Array#sort! (так, как один возвращает результаты в новом массиве, а другой работает над текущим объектом).Почему массив # срез и массив # срез! вести себя по-другому?

С sort первый (без перерыва), возвращает отсортированную копию текущего массива, а sort! сортирует текущий массив.

slice, возвращает массив с указанным диапазоном, и slice!удаляет указанного диапазона от текущего объекта.

По этой причине Array#slice! ведет себя как это вместо того, чтобы сделать текущий объект массивом с указанным диапазоном?

Пример:

a = [0,1,2,3,4,5,6,7,8,9] 

b = a.slice(2,2) 

puts "slice:" 
puts " a = " + a.inspect 
puts " b = " + b.inspect 

b = a.slice!(2,2) 
puts "slice!:" 
puts " a = " + a.inspect 
puts " b = " + b.inspect 

Выход:

slice: 
    a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    b = [2, 3] 
slice!: 
    a = [0, 1, 4, 5, 6, 7, 8, 9] 
    b = [2, 3] 

http://ideone.com/77xFva

+2

Использование '!'в методе не имеет заданного поведения, он просто указывает, что метод каким-то образом мутирует ввод, а также имеет тот же самый результат. Вы можете добавить его в конец любого метода, который вы пишете. – tpbowden

ответ

3

#slice и #slice! поведения эквивалентны: как «возвращение подмассив начиная с запуском индекса и продолжается в течение длины элементов», точно так же, как #sort и #sort! возвращает упорядоченный массив или #reverse и #reverse! возвращает обратным массив.

Разница в том, что методы взлома также изменяют сам объект.

a = [4,2,6,9,1,5,8] 
b = a.dup 
a.sort == b.sort!    # => true 
a == b      # => false 

b = a.dup 
a.reverse == b.reverse!  # => true 
a == b      # => false 

b = a.dup 
a.slice(2,2) == b.slice!(2,2) # => true 
a == b      # => false 
+0

Это не то, что пользователь спросил. Он знает об этом, он спрашивает о дизайнерском решении. В частности, почему ломтик! не заменяет текущий объект результатом. –

+2

'# slice' (и' #slice! ') _" Возвращает nil, если индекс выходит за пределы диапазона "_. Эта ситуация несовместима с идеей замены объекта возвращаемым значением – wacko

+0

, что, вероятно, является одним из лучших объяснений, которые я прочитал до сих пор. +1 –

1

! или взрывы методы в рубине, как правило, мутируют существующий объект, а не способ без взрыва эквивалента, который возвращает новый объект. Если вы хотите изменить существующий объект, используйте параметр метода bang.

EDIT: для решения дизайнерского решения, я не Matz, но я собираюсь предположить, что, поскольку природа slice заключается в возврате подмножества, он возвращает подмножество в каждом случае. Для других методов взлома, таких как gsub или sort, вы изменяете (потенциально) всю строку/объект, чтобы он либо возвращал копию, либо возвращал оригинал с изменениями.

+1

Это не то, что пользователь спросил. Он знает об этом, он спрашивает о дизайнерском решении. В частности, почему ломтик! не заменяет текущий объект результатом. –

+0

@SimoneCarletti, может быть, это помогает? –

0

Я думаю, что идея дизайнерского решения является то, что если вы звоните Array#slice!, то у вас уже есть указатель на срез массива (если вы назначили его в переменной). Логическое решение состоит в том, чтобы изменить объект, чтобы срез больше не находился в исходном массиве.

Вы можете видеть, как это было бы полезно в цикле, например. Если вы хотите сохранить кусочек первых трех элементов массива, сделайте что-нибудь с этими тремя элементами и остановитесь, когда их больше нет, вы можете использовать Array#slice!, и это в конечном итоге уничтожит массив.

Теперь, если вы представляете, что массив из примера был очередью или стеком, было бы разумно, почему вы хотите удалить части массива.

Смежные вопросы