别名实例变量在子类中

时间:2018-04-19 13:08:24

标签: ruby alias instance-variables

我希望为实例变量添加别名,因此别名可以在子类中使用(或者在类本身中使用)。 这是我想要实现的简化演示

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 

也不起作用。

2 个答案:

答案 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 = valueself.foo = value(如class A初始化程序中所示)。< / li>