0

我是 Ruby 新手,对如何创建Class类似于的方法感到困惑:attr_accessor,因为它将方法添加到用户类,但是这些添加的方法可以访问预初始化的实例变量。我很难解释,所以这里是我努力的一个大大简化的示例:

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s 
        new_var_name = "@crazy_var_name"

        instance_variable_set(new_var_name, ["hi", "everyone"])

        module_eval(%Q/
            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                return #{new_var_name}
            end
        /)
    end
end

这就是我尝试使用新方法Class修改我自己的类的方式:

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect

第一个放版画'1000'

第二个 puts prints 'nil',所以我的instance_variable_set调用super_accessor_wow似乎没有效果。

我预计第二个 puts 会'['hi', 'everyone']'顺便打印出来。所有这些代码都包含在一个 Ruby 文件中。

4

2 回答 2

1

您在类定义期间instance_variable_set调用时调用。super_accessor_wow该类的实例尚不存在。当您调用new. 您可以将@crazy_var_name初始化添加到构造函数中,也可以在greetings方法中定义它:

将默认值放在类变量中,并在构造函数中初始化实例变量(请注意,这会为您的类创建一个构造函数,如果您随后创建自己的构造函数,它将覆盖该构造函数):

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s
        new_var_name = "@crazy_var_name"
        new_var_name_default = "@#{new_var_name}"

        module_eval(%Q/
            #{new_var_name_default} = ["hi", "everyone"]

            def initialize()
              #{new_var_name} = #{new_var_name_default}
            end

            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                return #{new_var_name}
            end
        /)
    end
end

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect
puts Foo.class_variable_get('@@crazy_var_name').inspect
puts foo1.instance_variable_get('@crazy_var_name').inspect

输出:

1000
["hi", "everyone"]
["hi", "everyone"]
["hi", "everyone"]

greetings方法中定义它:

class Class
    def super_accessor_wow(attr_name)
        attr_name = attr_name.to_s
        new_var_name = "@crazy_var_name"

        module_eval(%Q/
            def super_#{attr_name}()
                return @#{attr_name}
            end

            def super_#{attr_name}=(value)
                @#{attr_name} = value
            end

            def greetings
                #{new_var_name} = ["hi", "everyone"] unless #{new_var_name}
                return #{new_var_name}
            end
        /)
    end
end

class Foo
    super_accessor_wow(:bar)
end

foo1 = Foo.new()
foo1.super_bar = 1000

puts foo1.super_bar
puts foo1.greetings.inspect

输出

1000
["hi", "everyone"]
于 2012-07-29T00:26:14.580 回答
0

如评论中所述, instance_variable_set 采用符号,而不是字符串,因此我们将首先修复它。

instance_variable_set(new_var_name.to_sym, ["hi", "everyone"])

但最大的问题是 instance_variable_set 不是由 Foo 的实例调用的,而是由 Foo 类本身调用的。因此,正在设置一个实例变量,但不是您所期望的。

Foo.instance_variable_get(:@crazy_var_name).inspect
# ["hi", "everyone"]
于 2012-07-29T00:26:55.453 回答