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

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

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

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

10 ответов


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

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 следуют ему. Это также поможет вам отслеживать, что изменить в коде.


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

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

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

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


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

именования 1.3.5

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

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


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

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


от themomorohoax.com:

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

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

2) Метод active record сохраняет запись или метод сохраняет объект (например, полоса!)

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

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

The bang предоставляет две подсказки другим разработчикам.

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

2) Когда вы вызываете метод, БД будет измененный.

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


наиболее точно сказать, что методы с треском! больше опасно или удивительно версия. Есть много методов, которые мутируют без взрыва, таких как .destroy и в целом методы имеют челку только там, где существует более безопасная альтернатива в основной lib.

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

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

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


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

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 навсегда. downcase! не вернет новый объект string, но заменит строку на месте, полностью изменив foo в downcase. Я предлагаю вам не использовать downcase! если это не абсолютно необходимо.


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

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]

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

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

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

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

или

foo = "word"
puts foo.capitalize

вместо

foo = "word"
foo.capitalize!
puts foo

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


!

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

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

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