Подтвердить что ты не робот

Когда оправдывается `eval` в Ruby?

"Предполагается, что "eval" является противным?" вдохновил этот:

В большинстве случаев все согласны с тем, что eval плохой, и в большинстве случаев есть более элегантная/безопасная замена.

Итак, я хотел спросить: если eval неправильно используется, действительно ли это нужно как функция языка? Это делает больше зла, чем пользы?

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

Изменить: Цель этого вопроса - получить как можно больше реальных случаев, когда eval является единственным или лучшим решением. Поэтому, пожалуйста, не входите в "если язык ограничивает направление творчества программиста".

Edit2: И когда я говорю eval, я, конечно, ссылаюсь на строку eval ing, не передавая ruby-блок на instance_eval или class_eval.

4b9b3361

Ответ 1

Единственный случай, который я знаю (кроме "У меня есть эта строка, и я хочу ее выполнить" ), динамически работает с локальными и глобальными переменными. Ruby имеет методы для получения имен локальных и глобальных переменных, но ему не хватает методов для получения или установки их значений на основе этих имен. Единственный способ сделать AFAIK - eval.

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

Обратите внимание, что, кстати, я говорю о string eval. Ruby также имеет instance_eval, который может принимать либо строку, либо блок для выполнения в контексте получателя. Блочная форма этого метода является быстрой, безопасной и очень полезной.

Ответ 2

Когда это оправдано? Я бы сказал, когда нет разумной альтернативы. Я мог подумать об одном использовании, где я не могу придумать альтернативу: irb, который, если вы копаете достаточно глубоко (до workspace.rb, вокруг строки 80 в моей копии, если вам интересно) использует eval для выполнения вашего ввод:

def evaluate(context, statements, file = __FILE__, line = __LINE__)
  eval(statements, @binding, file, line)
end

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

Ответ 3

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

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

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

Когда оправдано eval? В прагматичных терминах, когда вы это говорите. Если это ваша программа, и вы программист, вы устанавливаете параметры.

Ответ 4

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

Предположим, что вам передан блок, но (по какой-то причине) вам нужен доступ к объекту контекста привязки, вы бы сделали следующее:

obj = eval('self', block.binding)

Также полезно определить следующее:

class Proc
    def __context__
        eval('self', self.binding)
    end
end

Ответ 6

eval - это инструмент, он не является ни по своей природе хорошим, ни злым. Это оправдано, когда вы уверены, что это правильный инструмент для того, что вы пытаетесь выполнить.

Ответ 7

Инструмент вроде eval - это оценка кода во время выполнения и "компиляция". Вы знаете, что такое код при запуске Ruby? Тогда вам, вероятно, не понадобится eval. Является ли код генерации кода во время выполнения? то вам, вероятно, нужно это оценить.

Например, методы/функции, необходимые в рекурсивном приличном парсере, зависят от разбора языка. Если ваше приложение создает такой синтаксический анализатор "на лету", тогда имеет смысл использовать eval. Вы можете написать обобщенный синтаксический анализатор, но это может быть не столь элегантное решение.

"Программно заполняя letrec в Scheme. Макросы или eval?" это вопрос, который я опубликовал об eval на Схеме, где его использование в основном неизбежно.

Ответ 8

В целом eval - полезная функция языка, когда вы хотите запустить произвольный код. Это должно быть редкой вещью, но, возможно, вы делаете свой собственный REPL или хотите по какой-либо причине вывести рубиновую версию для конечного пользователя. Это может произойти, и поэтому функция существует. Если вы используете его для работы над некоторой частью языка (например, глобальных переменных), то либо язык испорчен, либо ваше понимание языка испорчено. Решение, как правило, не использует eval, но для лучшего понимания языка или выбора другого языка.

Стоит отметить, что в ruby ​​особенно instance_eval и class_eval используются другие применения.