Поведение методов Array bang
Некоторая ошибка в методах Array
похожа на compact!
, reject!
, flatten!
, uniq!
return nil
, если никаких изменений не было сделано:
[1,[2]].flatten!
# => [1, 2]
[1,2].flatten!
# => nil
[1,[2]].flatten
# => [1, 2]
[1,2].flatten
# => [1, 2]
[1,2,nil].compact!
# => [1, 2]
[1,2].compact!
# => nil
[1,2,nil].compact
# => [1, 2]
[1,2].compact
# => [1, 2]
Если они сделали это таким образом, должна быть причина. Любые идеи, что это может быть?
Ответы
Ответ 1
Методы bang (!
) модифицируют текущий объект на месте, но они возвращают nil
, если на нет соответствующих элементов. Это полезно, если по какой-либо причине вам нужно что-то сделать, если вы модифицировали данный массив.
if array.flatten!
puts "Oh yeah... flattened that array!"
end
Ответ 2
У меня всегда было впечатление, что bang версия методов Array
только разные в том смысле, что они изменить объект на месте.
Возможно, проблема заключается в том, что это впечатление не совсем правильное: согласно Дэвиду А. Черному, !
не означает, что метод изменяет приемник; !
означает, что этот метод является "опасной" версией другого эквивалентного метода, который имеет то же имя минус !
.
Теперь опасность принимает множество форм (внимание мое):
Иногда вы получаете более одного вида "опасности" даже в течение одного взрыва метод. Возьмите String#gsub!
. Эта метод изменяет приемник:
str = "David"
str.gsub!(/$/, " Black")
str # David Black
Он также отличается от gsub
(non-bang) в том случае, если строка не изменяется, gsub
возвращает копию неизменной string, но gsub!
возвращает nil:
str.gsub(/xyz/, "blah") # David Black
str.gsub!(/xyz/, "blah") # nil
str # David Black
The! в gsub!
дает вам хедз-ап: он предупреждает вас об опасности, и это означает что перед использованием метода вы должен точно выяснить, как это ведет себя. (Простой "ri String#gsub!
" должен это сделать.)
Эта семантика "хэдз-ап" также применяется к методам bang Array
.