【问题标题】:Cannot push into ruby array无法推入红宝石数组
【发布时间】:2012-03-03 20:41:19
【问题描述】:

我正在编写一个新的访问器,它有自己的数组变量来保存信息,但是当我尝试在其方法中调用 class_eval 时,该变量上的 push 方法不起作用。

它是用 Class 编写的方法,class_eval 行内容如下:

class_eval "def #{attr_name}=(value); #{attr_name} = value; #{information}.push value; end; def #{attr_name}_history; #{information}; end"

所以这一行的推送是行不通的。

【问题讨论】:

    标签: ruby arrays push


    【解决方案1】:

    您必须确保当您调用 class_eval 时本地变量 information 存储的任何字符串实际上是您要添加此函数的类上的一个方法。

    以下内容有效,因为我确保该类具有 history 方法。

    class A
      def history
        @history ||= []
      end
    end
    
    attr_name = "foo"
    information = "history"
    A.class_eval "def #{attr_name}=(value); #{attr_name} = value; #{information}.push value; end; def #{attr_name}_history; #{information}; end"
    
    a = A.new
    a.foo = "bar"
    a.foo = "baz"
    a.foo_history
    

    【讨论】:

    • 如果还有a.bar和a.another等等怎么办。这是否会保留这些变量的单独副本
    • 在本例中,attr_name 在执行class_eval 之前计算为“foo”,因此它只为一个参数添加历史记录。你可以编写一个 mixin,为你提到的每个变量运行这个逻辑,或者甚至查看 instance_variables 并自动添加它。
    【解决方案2】:

    它不起作用,因为“#{information}”将返回information字符串 值,而不是实际的Array 对象本身。这是因为它在构建时被替换为字符串。

    您必须将其更改为一个变量,该变量既属于您正在使用的对象的范围,也属于您正在处理的类。例如,尝试将其更改为:

    Foo::Information = [...]
    class_eval "
      class_eval "
      def #{attr_name}=(value)
        #{attr_name} = value
        Foo::Information.push value
      end
      def #{attr_name}_history
        Foo::Information
      end"
      "
    

    【讨论】:

      【解决方案3】:

      这是因为information变量应该被初始化为一个数组,然后你可以在它上面调用push方法。像这样的:

      def #{attr_name}=(value); 
        #{attr_name} = value; 
        (#{information}||=[]).push value; 
      end; 
      def #{attr_name}_history; 
        #{information}; 
      end
      

      顺便说一句,你的格式很丑,所以下次你必须三思而后行。

      【讨论】:

      • 我试图做多行但我无法让 %Q 在 IDE 上工作,如果你的意思是这样的话
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-10
      • 2012-09-13
      • 1970-01-01
      • 2017-06-15
      • 2014-01-05
      • 1970-01-01
      相关资源
      最近更新 更多