Почему в методах Ruby используются восклицательные знаки?

В Ruby некоторые методы имеют вопросительный знак (?), который задает вопрос типа include?, который спрашивает, включен ли рассматриваемый объект, затем возвращает истину / ложь.

Но почему у некоторых методов есть восклицательные знаки (!), а у других нет?

Что это значит?


person Lennie    schedule 04.03.2009    source источник
comment
синоним: взрыв, восклицательный знак   -  person prusswan    schedule 03.07.2012
comment
Принятый ответ следует изменить на stackoverflow.com/a/612653/109618. См. wobblini.net/bang.txt и ruby-forum.com/topic/176830#773946 - знак взлома означает, что версия с взрывом более опасна, чем без нее. аналог; обращаться с осторожностью - Матц   -  person David J.    schedule 31.07.2012
comment
Метод взрыва был бы отличным выбором, если бы только и все методы были опасными. К сожалению, это не так, и поэтому запоминание того, что является изменчивым, а что нет, становится утомительным упражнением.   -  person Damien Roche    schedule 04.09.2014


Ответы (10)


Как правило, методы, заканчивающиеся на !, указывают на то, что метод изменит объект, для которого он вызван. Ruby называет их «опасными методами», потому что они изменяют состояние, на которое может ссылаться кто-то другой. Вот простой пример для строк:

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo

Это выведет:

a string

В стандартных библиотеках есть много мест, где вы увидите пары методов с одинаковыми названиями, один с !, а другой без. Те, у которых нет, называются «безопасными методами», и они возвращают копию оригинала с изменениями, примененными к копии, без изменений вызываемого объекта. Вот тот же пример без !:

foo = "A STRING"    # a string called foo
bar = foo.downcase  # doesn't modify foo; returns a modified string
puts foo            # prints unchanged foo
puts bar            # prints newly created bar

Это выводит:

A STRING
a string

Имейте в виду, что это всего лишь соглашение, но многие классы Ruby следуют ему. Это также помогает вам отслеживать, что изменяется в вашем коде.

person Todd Gamblin    schedule 04.03.2009
comment
Также есть случаи, как выход против выхода! и (в рельсах) экономия против сохранения! - person Andrew Grimm; 05.03.2009
comment
Будьте очень осторожны - многие небольшие библиотеки не следуют этому соглашению. Если происходят странные вещи, часто заменяя obj.whatever! с obj = obj.whatever! исправляет это. Очень неприятно. - person Sarah Mei; 05.03.2009
comment
bang также используется для методов, которые вызывают исключение, когда метод без него не работает, например: save и save! в ActiveRecord - person ecoologic; 04.10.2011
comment
Какая экономия! на самом деле в Rails? - person Abhi; 23.12.2013
comment
@AbhilashAK save! выдает ошибку, если это не может спасти. Это противоположно обычному сохранению, возвращающему истину / ложь. - person BookOfGreg; 16.02.2014
comment
@tgamblin В Ruby есть множество методов, которые изменяются без каких-либо проблем. Есть даже редкие методы, которые не видоизменяются, но делают что-то удивительное, например, вызывают ошибки или пропускают ошибки. Говорят, что это более необычная версия метода, и я думаю, это должно быть отражено в вашем ответе, поскольку он отмечен как правильный. - person BookOfGreg; 16.02.2014
comment
Ха! Я люблю это. Какой до неприличия сумасшедший язык. - person Darth Egregious; 17.09.2014
comment
@ecoologic Я приехал сюда после того, как узнал об использовании ! из здесь. Как мы можем узнать больше об этом использовании? (и кажется странным использовать один и тот же символ для двух совершенно разных вещей? Интересно, почему был сделан этот выбор дизайна) - person stevec; 09.09.2020
comment
ActiveRecord - хороший пример загадочного поведения (изменчивости), вам нужно вызвать valid? (это сделает save), чтобы заполнить ошибки. Взрыв также используется для опасных методов, генерирующих исключения, например save!. Это расплывчатое соглашение, на которое нельзя слишком полагаться. Я предлагаю вам разъяснить команде, что вы имеете в виду ! для всех проектов. - person ecoologic; 10.09.2020

Восклицательный знак означает множество вещей, и иногда вы не можете сказать многое, кроме «это опасно, будьте осторожны».

Как говорили другие, в стандартных методах он часто используется для обозначения метода, который заставляет объект видоизменяться, но не всегда. Обратите внимание, что многие стандартные методы меняют свой приемник и не имеют восклицательного знака (pop, shift, clear), а некоторые методы с восклицательными знаками не меняют своего получателя (exit!). См., Например, эту статью.

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

Это соглашение об именах, но многие люди используют его несколько иначе. В вашем собственном коде хорошее правило - использовать его всякий раз, когда метод делает что-то «опасное», особенно когда существуют два метода с одинаковым именем, и один из них более «опасен», чем другой. «Опасно» может означать что угодно.

person Brian Carper    schedule 04.03.2009

Это соглашение об именах взято из схемы.

1.3.5 Соглашения об именах

По соглашению имена процедур, которые всегда возвращают логическое значение, обычно заканчиваются на ``? ''. Такие процедуры называются предикатами.

По соглашению, имена процедур, хранящих значения в ранее выделенных местах (см. Раздел 3.4), обычно заканчиваются на ``! ''. Такие процедуры называются процедурами мутации. По соглашению значение, возвращаемое процедурой мутации, не указано.

person Steven Huwig    schedule 04.03.2009
comment
+1 к этому ответу, так как есть документация, которая дает разумные объяснения для! использование. Действительно хороший ответ Стивен - person DavidSilveira; 09.12.2016
comment
Спасибо, @DavidSilveira! - person Steven Huwig; 06.01.2017

! обычно означает, что метод воздействует на объект, а не возвращает результат. Из книги Programming Ruby:

Методы, которые являются «опасными» или модифицируют получатель, могут быть названы с завершающим знаком «!».

person Pesto    schedule 04.03.2009

Правильнее всего сказать, что методы на ура! являются более опасными или удивительная версия. Есть много методов, которые видоизменяются без взрыва, например .destroy < / a> и, как правило, методы работают только там, где более безопасная альтернатива существует в основной библиотеке.

Например, в Array у нас есть .compact и .compact!, оба метода изменяют массив, но .compact! возвращает nil вместо self, если в массиве нет nil, что более удивительно, чем просто возврат self.

Единственный немутантный метод, который я нашел с треском, - это Kernel's _ 6_, что более удивительно, чем .exit, потому что вы не можете поймать SystemExit, пока процесс завершается.

Rails и ActiveRecord продолжают эту тенденцию в том, что они используют взрыв для более «неожиданных» эффектов, таких как .create!, который вызывает ошибки при сбое.

person BookOfGreg    schedule 15.02.2014

С сайта themomorohoax.com:

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

1) Активный метод записи вызывает ошибку, если метод не выполняет то, что обещает.

2) Активный метод записи сохраняет запись или метод сохраняет объект (например, полосу!)

3) Метод делает что-то «лишнее», например, отправляет куда-то или выполняет какое-то действие.

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

Взрыв дает две подсказки другим разработчикам.

1), что нет необходимости сохранять объект после вызова метода.

2) когда вы вызываете метод, db будет изменен.

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods

person Edward Castaño    schedule 09.09.2011

Простое объяснение:

foo = "BEST DAY EVER" #assign a string to variable foo.

=> foo.downcase #call method downcase, this is without any exclamation.

"best day ever"  #returns the result in downcase, but no change in value of foo.

=> foo #call the variable foo now.

"BEST DAY EVER" #variable is unchanged.

=> foo.downcase! #call destructive version.

=> foo #call the variable foo now.

"best day ever" #variable has been mutated in place.

Но если вы когда-либо вызывали метод downcase! в приведенном выше объяснении, foo навсегда изменится на нижний регистр. downcase! не вернет новый строковый объект, а заменит строку на месте, полностью изменив foo на нижний регистр. Я предлагаю вам не использовать downcase!, если в этом нет крайней необходимости.

person Mirage    schedule 14.09.2013

!

Мне нравится думать об этом как о взрывном изменении, которое разрушает все, что было до него. Взрыв или восклицательный знак означает, что вы вносите в свой код постоянное сохраненное изменение.

Если вы используете, например, метод Ruby для глобальной подстановкиgsub! сделанная вами подстановка будет постоянной.

Другой способ, который вы можете себе представить, - это открыть текстовый файл и выполнить поиск и замену с последующим сохранением. ! делает то же самое в вашем коде.

Еще одно полезное напоминание, если вы пришли из мира bash, sed -i имеет тот же эффект, что и постоянные сохраненные изменения.

person Charlie Wood    schedule 03.04.2017

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

Используйте ! только в том случае, если вы не планируете хранить исходное значение в переменной, для которой вы вызвали метод.

Я предпочитаю делать что-то вроде:

foo = "word"
bar = foo.capitalize
puts bar

OR

foo = "word"
puts foo.capitalize

Вместо того

foo = "word"
foo.capitalize!
puts foo

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

person Charles    schedule 23.07.2015
comment
Потому что ваш ответ никоим образом не помог. Нижняя линия: ! методы просто изменяют значение объекта, к которому они обращаются, просто неверно. - person Darwin; 08.08.2016
comment
@Darwin он действительно изменяет значение объекта. ! изменяет объект, а не возвращает измененную копию. - person Charles; 08.08.2016
comment
Как вы думаете, что это делает? User.create! - person Darwin; 09.08.2016
comment
@ Дарвин, в каком контексте? ActiveRecord? - person Charles; 10.08.2016
comment
Да, ActiveRecord. - person Darwin; 10.08.2016
comment
Вот лучший аргумент в пользу того, почему ваши ответы явно неверны. Прочтите комментарий Матца на bang !. ruby-forum.com/topic/176830#773946. Вы все еще чувствуете, что ваш Итог:! методы просто изменяют значение объекта, к которому они обращаются, истинно в любом случае, что бы то ни было? - person Darwin; 10.08.2016
comment
@ Дарвин: Совершенно верно? Нет, и теперь я это понимаю. В любом случае? да. Очевидно, что изменение его аргумента или объекта, для которого вызывается метод !, опасно - это само собой разумеется; любой метод, который изменяет любой из своих аргументов, является опасным, потому что вы можете потерять данные. Признаюсь: меня учили, что ! изменяет свой объект, и я никогда не сомневался в этом. Так что я благодарю вас за это. - person Charles; 11.08.2016

Названные «деструктивные методы». Они имеют тенденцию изменять исходную копию объекта, о котором вы говорите.

numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers   # returns [nil,nil,nil,nil,nil]
person Mittinti Ramana Murthy    schedule 23.05.2017