Как лучше всего использовать Ruby, чтобы избежать неправильного использования присваивания «=»?

StackOverflow https://stackoverflow.com/questions/5443068

Вопрос

Меня пару раз укусили, когда я забыл об этом x = y в Ruby x относится к тому же объекту, что и y;Я слишком привык к языкам, где в терминах Ruby это означает: x = y.dup.Забыв об этом, я нечаянно меняю y когда я думаю, что на правой стороне задания безопасно.

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

name = (person.last_name.blank? ? 'unknown' : person.last_name)

где позже name << title на самом деле будет меняться person.last_name, а не только имя.

Если это случилось и с вами, как вы научились этого избегать?Есть ли определенные тревожные сигналы или закономерности, на которые следует обращать внимание?Вы с подозрением относитесь к каждому заданию, которое делаете?Вы используете .dup много?Я не знаю, станет ли когда-нибудь использование Ruby моей второй натурой, поэтому буду рад любым полезным советам.

Это было полезно?

Решение

Это может показаться неортодоксальным для такого (по сути императивного) языка, как Ruby, но мой совет таков:избегать сопутствующий ущерб вообще не обновляя объекты (кроме случаев крайней необходимости);вместо этого создайте новые.Вы платите немного за производительность, но получаете более понятный, компактный, модульный и простой в отладке код.

http://en.wikipedia.org/wiki/Functional_programming

Итак, в вашем примере просто создайте новую строку с новым именем:

complete_name = name + title

Другие советы

Просто дополнение к ответу Токланда:

Функциональный подход настаивает на неизменность - т.е.не изменяя существующие объекты, а создавая новые всякий раз, когда вы хотите изменить исходный.Это несколько противоречит объектно-ориентированной парадигме, которую также предлагает Ruby (объекты сохраняют свое внутреннее состояние, которое можно изменить, вызывая в нем методы), поэтому вам придется немного балансировать между двумя подходами (с другой стороны, мы получаем выгоду). благодаря наличию нескольких парадигм, легко доступных на одном языке).

Итак, на данный момент следует запомнить три вещи:

  1. Узнайте, что такое назначение в Ruby:ничего, кроме названия объекта.Итак, когда вы говорите y=x, вы всего лишь говорите "мы даем другое имя y тому, что было названо x".
  2. name << title мутирует объект под названием name.
  3. name += title принимает объекты с именем name и title, объединяет их в другой объект и присваивает этому новому имени объекта name.Это ничего не мутирует.

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

hash = {....}
filename = object.file_name
hash.each |k, v| {file_name.gsub!(k, v) if file_name.include? k}

Этот код находился внутри цикла, и в этом цикле я ожидал, что переменная file_name чтобы снова установить исходное значение.Но имя объекта.file_name было изменено, когда я выполнял file_name.gsub!.Есть 2 способа решить эту проблему.Либо замените .gsub! позвонить с file_name = file_name.gsub или сделай file_name = object.file_name.dup.Я выбрал второй вариант.

Я думаю, нам следует быть осторожными с методами, имеющими ! и <<, поскольку они изменяют исходный объект, над которым действуют, особенно после подобных заданий.

Метод не должен изменять переменную (например,с помощью оператора сдвига), если только в его определении не указано, что он его изменит.

Так:никогда не изменяйте объект в методе, который либо (а) не создал его, либо (б) не документировал, что он его изменяет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top