2009-03-04 5 views
418

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

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

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

+15

синоним: взрыв, восклицательный знак – prusswan

+15

Принятый ответ должен быть изменен на http://stackoverflow.com/a/612653/109618. См. Http://www.wobblini.net/bang.txt и http://www.ruby-forum.com/topic/176830#773946 - «Знак взрыва» означает, что версия бэнга более опасна, bang counterpart; обращайтесь с осторожностью »« -Matz –

+2

Метод взлома будет отличным выбором дизайна, если ** только ** и ** все ** bang-методы были опасны. К сожалению, это не так, и поэтому это становится расстраивающим упражнением по запоминанию того, что есть и не изменяет. –

ответ

498

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

Есть также такие случаи, как exit to exit! и (в рельсах) сохранить по сравнению с сохранением! –

+13

Будьте очень осторожны - многие небольшие библиотеки не следуют этому соглашению.Если странные вещи происходят, часто заменяя obj.whatever! с obj = obj.whatever! исправляет его. Очень расстраивает. –

+73

bang также используется для методов, которые вызывают исключение, когда метод без него не выполняется, например: 'save' и' save! 'В' ActiveRecord' – ecoologic

23

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

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

56

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

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

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

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

+1

+1 к этому ответу, так как есть документация, которая дает разумные объяснения! Применение. Действительно хороший ответ Steven – DavidSilveira

+0

Спасибо @DavidSilveira! –

118

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

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

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

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

13

От themomorohoax.com:

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

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

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

3) Способ делает что-то «дополнительное», как посты, чтобы куда-нибудь, или же некоторые действия.

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

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

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

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

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

6

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

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

13

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

Например, на массиве мы имеем .compact и .compact!, оба метода мутировать массив, но .compact! возвращает NIL вместо себя, если нет нильполугруппы находится в массиве, что более удивительно, чем просто возвращение себя.

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

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

+0

Я делаю upvote для упоминания о 'nil'. – Nakilon

0

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

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

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

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

ИЛИ

foo = "word" 
puts foo.capitalize 

Вместо

foo = "word" 
foo.capitalize! 
puts foo 

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

+0

Почему это было забито !? – Charles

+1

Потому что ваш ответ никоим образом не помог. «Нижняя строка:! Методы просто изменяют значение объекта, на который они вызваны», просто неверно. – Darwin

+0

@Darwin это _does_ изменить значение объекта. '!' мутирует объект, а не возвращает измененную копию. – Charles

0
! 

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

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

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

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

1

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

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] 

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

  • Нет связанных вопросов^_^