我希望为实例变量添加别名,因此别名可以在子类中使用(或者在类本身中使用)。 这是我想要实现的简化演示
class A
attr_reader :bar
alias :foo :bar
def initialize
@bar = 'hello'
end
end
class B < A
def try_alias
puts @foo
end
end
B.new.try_alias #=> "hello"
但它不起作用,@ foo是零。有办法以某种方式实现它吗?或者,每当我更改@bar以模仿此行为时,是否必须更改/设置@foo?
编辑:似乎我试图做别名的方式如果被调用foo
而不是
@foo
在try_alias方法中,这并不奇怪。试图使用
alias :@foo :bar
也不起作用。
答案 0 :(得分:0)
attr_reader :bar
创建一个&#34; getter&#34; @bar
的方法,省去了自己做的麻烦:
def bar
@bar
end
(见Module#attr_reader)。要为方法bar
创建别名,请编写
alias :foo :bar
实际上与为名为@bar
的{{1}}创建第二个getter相同:
foo
因此def foo
@bar
end
缩减为puts foo
。
答案 1 :(得分:0)
您应在原始别名@foo
中明确使用setter
;只会在您的代码中添加一行。
A
成为超类时,通常
想要在设置某些变量(例如@bar
)之前进行验证。这就是将验证功能添加到下面的代码中的原因(只是为了反映这个想法)。此外,由于attr
的声明将转换为methods
,因此方法是掌握最终行为的方法,因此,通常,最好使用alias_method
别名(请参阅this widely accepted answer)。
我敢说这是最简单的方法:
module Aside
class A
attr_reader :bar
# as mentioned, preferable to use alias_method
alias_method :foo, :bar
alias_method :foo=, :bar=
def initialize
# use setter method to keep @bar and @foo in sync
self.bar = 'hello'
end
def bar=(value)
@bar = nil
@bar = value if some_validation?(value)
@foo = @bar
end
private
def some_validation?(value)
value.is_a?(String)
end
end
class B < A
def try_alias
puts @foo
end
end
end
Aside::B.new.try_alias #=> "hello"
请注意,initialize
中的class A
使用setter method
而不是直接分配(如您的示例)来初始化@bar
。 / p>
这是因为在以这种方式进行别名之后,为了保持@bar
和@foo
的同步,您应该避免在bar setter
本身以外的任何地方进行直接变量赋值(注意:这很好还是要练习,因为您将@foo
的所有验证集中到一个点)。
换句话说,当您想使用这种方法时:
direct assignment
: @bar = value
或@foo = value
,并且setter methods
代替: self.bar = value
或self.foo = value
(如class A
初始化程序中所示)。< / li>