在Ruby中,您可以通过在类定义中添加以下内容来创建getter / setter方法。
attr_reader :key1, :key2, :key4
attr_writer :key1, :key2, :key3
或等效
attr_accessor :key1, :key2, :key3
例如
class Foo
attr_reader :blah, :bar, :foo, :rah, :jar
def initialize a, b, c
@blah = calculate_blah(a,b)
@bar = calculate_bar(a)
@foo = calculate_foo(b,c)
@rah = calculate_rah(a,b,c)
@jar = calculate_jar(a,c)
end
# etc etc
end
假设有很多实例变量,我想要getter方法 所有这些。
是否可以在所有实例变量上声明attr_reader
而不将它们全部列出来?
这样做的好处是,您不必在initialize
方法中维护两个变量列表(相同),另一个列在attr_reader
。所以稍后如果你想添加另一个实例变量,你只需要在initialize
方法中设置它,而不需要将它添加到attr_reader
列表中。
如果attr_reader
无法提供此功能,可能会召唤一些元编程来帮助吗?
这里的主要目标是了解Ruby中是否可行。 使用元编程通常会导致性能和默默无闻的成本。但这超出了这个问题的范围。
我更想知道是否可以做某事,而不是这是否正确。
答案 0 :(得分:4)
这是使用单例方法的解决方案。注意create_getters
是一种私有方法,因此外界并未意识到使用元编程(实现细节)。
class Foo
def initialize a, b
@foo = a + b
@bar = a - b
@jar = a + b + 1000
create_getters
end
private
def create_getters
instance_variables.each do |v|
define_singleton_method(v.to_s.tr('@','')) do
instance_variable_get(v)
end
end
end
end
在irb中运行:
2.2.1 :082 > x=Foo.new 100, 99
=> #<Foo:0x007fb4f3c31ce8 @foo=199, @bar=1, @jar=1199>
2.2.1 :083 > x.foo
=> 199
2.2.1 :084 > x.bar
=> 1
2.2.1 :085 > x.jar
=> 1199
警告:通过这种方式,对象实例化和getter方法调用都是SLOWER。
答案 1 :(得分:1)
尽管正如其他人所说,实际使用类似代码并不是一个好主意,但是可以编写你要求的元函数。 这是许多可能的不同解决方案之一。我们的想法是,在对象上已经定义了实例变量时,可以在生命周期中扩充一次使用的每个对象。这可能发生在初始化期间或之后。
class Foo
def initialize
@a = @b = @c = 33
# you could call define_attr_readers here
end
def define_attr_readers
# get the eigenclass of the current object
klass = class << self; self; end
symbols = instance_variables.map { |s|
# remove the @ at the start of the symbol
s.to_s[1..-1].to_sym
}
# augment the eigenclass
klass.class_eval do
symbols.each do |s|
attr_reader s
end
end
end
end
f = Foo.new
f.define_attr_readers
p f.a, f.b, f.c
答案 2 :(得分:1)
假设
class A
def initialize
@b=0
@c=1
end
end
然后
a = A.new
a.instance_variables.each { |iv| self.class.send(:attr_reader, iv.to_s[1..-1].to_sym) }
a.b #=> 0
a.c #=> 1
如果在initialize
中定义了所有实例变量,则可以编写
class A
def initialize
@b=0
@c=1
end.tap { |instance| instance.instance_variables.each { |iv|
self.class.send(:attr_reader, iv.to_s[1..-1].to_sym) } }
end
a = A.new
a.b #=> 0
a.c #=> 1
答案 3 :(得分:0)
实例化一次类以评估实例变量并重新定义类
class Hey
def initialize
@foo, @bar, @shabaz = [1,2,3]
end
end
Hey.new.instance_variables.tap do |inst_vars|
Hey.class_eval do
attr_reader *inst_vars.map { |var| var.to_s.sub(/^@/, '').to_sym }
end
end
p Hey.new.foo
p Hey.new.bar
p Hey.new.shabaz