Какова цель "!" а также "?" в конце имен методов?

Иногда я вижу методы в Ruby, которые имеют?? а также "!" в конце их, например:

name = "sample_string"
name.reverse
name.reverse!
name.is_binary_data?

Мне было интересно, какова их цель? Являются ли они просто синтаксическим покрытием из сахара?

Ответ 1

Это "просто сахарное покрытие" для удобочитаемости, но они имеют общие значения:

  • Методы, заканчивающиеся на !, выполняют некоторые постоянные или потенциально опасные изменения; например:
    • Enumerable#sort возвращает отсортированную версию объекта, а Enumerable#sort! сортирует его на месте.
    • В Rails ActiveRecord::Base#save возвращает false, если сохранение завершилось неудачно, а ActiveRecord::Base#save! вызывает исключение.
    • Kernel::exit вызывает выход script, а Kernel::exit! делает это немедленно, минуя любые обработчики выходных данных.
  • Методы, заканчивающиеся на ?, возвращают логическое, что делает поток кода еще более интуитивно похожим на предложение - if number.zero? читается как "если число равно нулю", но if number.zero просто выглядит странно.

В вашем примере name.reverse оценивает обратную строку, но только после того, как строка name.reverse! содержит переменную name, на самом деле содержит обратное имя. name.is_binary_data? выглядит как "есть name двоичные данные?".

Ответ 3

В Ruby ? означает, что метод возвращает логическое значение, а ! изменяет объект, на который он был вызван. Они предназначены для улучшения читаемости при просмотре кода.

Ответ 4

В отличие от - я полагаю - большинство языков программирования...

Ruby, методам разрешается заканчивать вопросительными знаками или восклицательными знаками.

По соглашению методы, которые отвечают на вопросы (т.е. Array # empty? возвращает true, если приемник пуст) заканчиваются знаками вопроса.

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

От: http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/, раздел Смешные имена методов

Ответ 5

Остерегайтесь, это не всегда так. Возьмем, к примеру, Ruby Array # concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat.

Если вы можете сильно сгореть, это что-то вроде MyActiveRecordModel.column_names.concat([url]). Более поздние вызовы, связанные с MyActiveRecordModel, попытаются найти столбец "url" для MyActiveRecordModel и throw.

Вместо этого вы должны клонировать его перед выполнением concat. К счастью, мой набор тестов поймал этот, но... хедз-ап!