【问题标题】:Create attr_reader methods while setting the values for the according instance variables in the initialize method?在初始化方法中设置相应实例变量的值时创建 attr_reader 方法?
【发布时间】:2012-03-17 22:50:58
【问题描述】:

我正在寻找方法来创建相应的 attr_reader 方法,同时在初始化方法中设置相应实例变量的值?例如以下代码:

class SomeClass
  attr_reader :hello
  def initialize( arg)
    @hello = arg
  end
end

我正在寻找如下写法:

class SomeClass
  def initialize( arg)
    some_method_as_described_in_question( @hello, arg) 
  end
end   

Ruby 内置类和模块中是否存在我所描述的方法?

【问题讨论】:

  • 不,没有这种方法。
  • 这似乎很方便,是访问控制的问题吗?为什么不包括在内?
  • 在实例方法 (initialize) 中包含一个您调用的方法可能会很奇怪,该方法会更改类上的内容,即其他实例上也是如此。还是您只希望它在当前实例上设置阅读器?你可以在 Ruby 1.9 中使用 define_singleton_method 来做到这一点:gist.github.com/be3485dde76c0da72a00 也许你可以澄清这个问题?
  • @KurtRudolph,因为目前还不清楚具体会做什么。如果它应该在类中添加一个成熟的属性读取器,那么将它放在初始化方法中是没有意义的。然后每次创建一个新对象时,它都会在类级别上执行相同的属性分配。如果您想在 eigenclass 上执行此操作,以便为每个实例动态设置属性读取器,请参阅我的答案。如果只是为了“方便”,那么它甚至没有意义,因为它会做一些无用或不同的事情。

标签: ruby ruby-1.9


【解决方案1】:

您可以从方法中打开特征类并在那里设置属性:

class SomeClass
  def initialize(arg)
    (class << self; self; end).send(:attr_reader, :hello)
    @hello = arg
  end
end

这样每个实例的特征类都将具有该属性读取器。但实际上,只有当属性名称是动态的并且可能因实例而异时,这样做才有意义。如果它总是hello,我认为像原始代码块一样在类中定义它没有任何缺点。

例如,如果你动态地传入属性名,你可以这样做:

class SomeClass
  def initialize(attr, arg)
    (class << self; self; end).send(:attr_reader, attr.to_sym)
    instance_variable_set("@#{attr}", arg)
  end
end

这与 Ruby 1.8 兼容。在对您的问题的评论中从@HenrikN 获得提示,您可以在 Ruby 1.9 中使用 define_singleton_method

class SomeClass
  def initialize(attr, arg)
    define_singleton_method(attr) { instance_variable_get("@#{attr}") }
    instance_variable_set("@#{attr}", arg)
  end
end

【讨论】:

  • 非常非常好!根据我自己的理解,您是否会确认这是否正确:class &lt;&lt; self 在某种意义上为其自身的类创建了一个附加定义,返回作为其自身定义对象的对象,并通过send(:attr_reader, :hello) 创建想要attr_reader?
  • @KurtRudolph,是的,这非常正确。只要确保你明白每个对象实例都有它自己的类。您可以将影响该实例的方法放在那里,而不影响该类的其他实例。而“class
  • @KurtRudolph,我撤消了您对我的回答的编辑。您的编辑是不同,而不仅仅是更简单。您链接到的 Henrik 的要点使其“hello”始终返回 arg 的 initial 值,因此它的工作方式与属性读取器完全不同。我拥有它的方式,它对属性读取器完全相同工作,因此您可以设置@hello = ... 并获得预期的obj.hello 属性。
  • 感谢您的回复,您已经多次回答了我的问题,并且每次回答都措辞得当且透彻。不仅如此,您还花时间帮助我理解问题的原因,而不仅仅是告诉我如何解决当前问题。干杯本利
【解决方案2】:

不确定我是否理解这个问题,但您可以使用 Struct 获取初始化程序和访问器方法:

class SomeClass < Struct.new(:hello)
end

x = SomeClass.new("yo")
puts x.hello  # "yo"
x.hello = "what up"
puts x.hello  # "what up"

【讨论】:

  • 这不是我要找的。我部分想要它用于动态目的,我部分想要它只是因为我试图不重复我自己,只是在一个命令中声明与实例变量一起应该有允许访问它的相应方法,即p = SomeClass.new 'world'; puts p.hello' should output the string world ` 无需单独声明attr_reader :hello@hello = arg
【解决方案3】:
require 'ostruct'

p = OpenStruct.new
p.hello = 'world'
p.could_be_anything = 'nothing'
puts p.hello #=> 'world'
puts p.could_be_anything #=> 'nothing'

【讨论】:

    猜你喜欢
    • 2011-09-24
    • 2010-12-01
    • 2016-02-13
    • 1970-01-01
    • 2017-10-23
    • 2010-10-06
    • 1970-01-01
    • 2010-10-18
    • 2022-11-16
    相关资源
    最近更新 更多