代码之家  ›  专栏  ›  技术社区  ›  Mladen Jablanović

Ruby中的'eval'什么时候是对的?

  •  25
  • Mladen Jablanović  · 技术社区  · 16 年前

    Is 'eval' supposed to be nasty? “启发了这一点:

    eval 不好,在大多数情况下,有更优雅/更安全的替代品。

    所以我想问:如果 是否经常被误用,是否真的需要将其作为一种语言功能?它做的坏事比好事多吗?

    伊迪丝2:当我说 评估 评估 instance_eval class_eval .

    8 回复  |  直到 9 年前
        1
  •  26
  •   Chuck    16 年前

    我知道的唯一情况(除了“我有这个字符串,我想执行它”)是动态处理局部和全局变量。Ruby有获取局部变量和全局变量名称的方法,但缺少基于这些名称获取或设置其值的方法。唯一的办法就是用 eval

    任何其他用途几乎肯定是错误的。我不是大师,也不能明确地说没有其他人,但我见过的每一个其他用例都有人说“你需要评估这个”,我找到了一个没有的解决方案。

    注意,我说的是 顺便说一下,这里。Ruby也有 instance_eval ,它可以在接收方的上下文中执行字符串或块。这种方法的块形式是快速、安全和非常有用的。

        2
  •  16
  •   Mike Woodhouse    16 年前

    什么时候是合理的?如果没有合理的选择,我会说。我能想到一个我想不出替代方案的用途:irb,如果你挖得足够深(到 workspace.rb ,如果您感兴趣,请参见我的副本第80行)使用eval执行输入:

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

    这对我来说似乎很合理——在这种情况下,在被要求执行代码的那一刻之前,你根本不知道要执行什么代码。一些动态和互动的东西似乎符合这个要求。

        3
  •  14
  •   tadman    16 年前

    eval之所以存在是因为当你需要它的时候,当你真的需要它的时候,没有替代品。毕竟,通过创造性的方法调度,您可以做的事情只有这么多,而且在某些时候,您需要执行任意代码。

    仅仅因为一种语言有一个可能是危险的特性并不意味着它天生就是一件坏事。当一种语言假定知道的比它的使用者多时,就有麻烦了。

    我认为,当你发现一种编程语言没有危险时,你就会发现它不是很有用。

    评估何时合理?用实用主义的话来说,当你说是的时候。如果是你的程序,而你是程序员,你可以设置参数。

        4
  •  6
  •   horseyguy    16 年前

    有一个非常重要的用例 eval() 这(AFAIK)不能使用任何其他方法实现,也就是为绑定找到相应的对象引用。

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

    定义以下内容也很有用:

    class Proc
        def __context__
            eval('self', self.binding)
        end
    end
    
        5
  •  5
  •   the Tin Man    13 年前

    IMO主要针对特定领域的语言。

    " Evaluation Options in Ruby

        6
  •  4
  •   Bryan Oakley    16 年前

    评估是一种工具,它既不是天生的善也不是恶。只要你确信它是你想要完成的事情的正确工具,它就是合理的。

        7
  •  2
  •   Community Mohan Dere    9 年前

    像eval这样的工具是在运行时对代码进行评估,而不是在“编译”时。您知道启动Ruby时的代码是什么吗?那么你可能不需要评估。您的代码是否在运行时生成代码?那你可能需要评估一下。

    " Programatically filling in a letrec in Scheme. Macros or eval? “这是我在Scheme中发布的一个关于eval的问题,在Scheme中使用eval是不可避免的。

        8
  •  2
  •   olleicua    11 年前

    一般来说 eval 当您想要运行任意代码时,它是一种有用的语言功能。这应该是一件罕见的事情,但可能您正在制作自己的REPL,或者出于某种原因希望向最终用户公开ruby运行时。它可能会发生,这就是该功能存在的原因。如果您使用它来处理语言的某些部分(例如全局变量),则可能是该语言有缺陷,或者您对该语言的理解有缺陷。解决方案通常不是使用eval,而是更好地理解语言或选择不同的语言。

    值得注意的是,在ruby中 instance_eval class_eval 还有其他用途。

        9
  •  1
  •   Ian    5 年前

    eval 定期甚至没有意识到这一点;这是rubygems加载Gemspec内容的方式。通过 rubygems/lib/specification.rb :

      # Note: I've removed some lines from that listing to illustrate the core concept
      
      def self.load(file)
       
        code = File.read(file)
        begin
          _spec = eval code, binding, file       #  <--------  EVAL HAPPENS HERE 
    
          if Gem::Specification === _spec
            return _spec
          end
    
          warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)."
        rescue SignalException, SystemExit
          raise
        rescue SyntaxError, Exception => e
          warn "Invalid gemspec in [#{file}]: #{e}"
        end
    
        nil
      end
    

    gem specification would look like this

    Gem::Specification.new do |s|
      s.name        = 'example'
      s.version     = '0.1.0'
      s.licenses    = ['MIT']
      s.summary     = "This is an example!"
      s.description = "Much longer explanation of the example!"
      s.authors     = ["Ruby Coder"]
      s.email       = 'rubycoder@example.com'
      s.files       = ["lib/example.rb"]
      s.homepage    = 'https://rubygems.org/gems/example'
      s.metadata    = { "source_code_uri" => "https://github.com/example/example" }
    end
    

    请注意,gempec文件只是创建一个新对象,但不分配它,也不将它发送到任何地方。 试图 load require 此文件(甚至使用Ruby执行)不会返回 Gem::Specification 价值 评估 是提取数据的唯一方法 价值 由外部ruby文件定义。

        10
  •  0
  •   conanite    4 年前

    eval的一个用途是将另一种语言编译为ruby:

    ruby_code = "(def foo (f a b) (mapv f (cons a b)))".compile_to_ruby
    # "foo_proc = ->(f a b) { mapv_proc.call(f, (cons_proc.call(a, b)) }"
    eval ruby_code
    
        11
  •  0
  •   Burak Kaymakci    4 年前

    我使用一个实现Ruby的3D建模软件来编写自定义文本宏。在该软件中,我们可以访问以下形式的模型数据: name:value

    owner.name
    #=> value
    

    因此,对于36英寸高的机柜,我可以访问高度并将其值转换为英尺,如下所示:

    owner.height.to_f / 12
    

    主要的问题是,该软件中的对象没有唯一的标识符,只有一个称为对象的标识符 schedule_number 附表编号 在变量名中,以便我可以在其他地方调用和使用该值,我知道的唯一可行方法是使用eval:

    eval "#{owner.schedule_number} = owner.height"