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

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

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

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

Ответ 1

В общем, методы, заканчивающиеся на !, указывают, что метод изменит объект, на который он вызвал. 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. Это также помогает вам отслеживать, что изменяется в вашем коде.

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

От themomorohoax.com:

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

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

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

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

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

Бэг предоставляет две рекомендации другим разработчикам.

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

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

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

Ответ 6

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

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

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

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

Ответ 7

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

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!, если это не является абсолютно необходимым.

Ответ 8

Вызывается "Деструктивные методы". Они имеют тенденцию изменять исходную копию объекта, на который вы ссылаетесь.

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]

Ответ 9

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

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

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

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

ИЛИ

foo = "word"
puts foo.capitalize

Вместо

foo = "word"
foo.capitalize!
puts foo

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

Ответ 10

!

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

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

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

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