【问题标题】:Object#send with attr_reader [duplicate]Object#send with attr_reader [重复]
【发布时间】:2019-06-11 07:41:27
【问题描述】:

看这段代码:

class Person
  attr_accessor :name, :age

  def initialize(data)
    data.each { |k, v| self.send("#{k}=", v) }
  end
end

data = {
  name: 'Luke Skywalker',
  age: 19
}

person = Person.new(data)

person.inspect # => #<Person @name="Luke Skywalker", @age=19>

这很好用。它做它应该做的事情。问题是,我不希望属性是可变的,换句话说,我想使用attr_reader。我知道如果我使用attr_reader Ruby 不会为我创建编写器方法(def attr=(val) ...),因此我将无法在send 中使用"#{k}="。我真的不想这样做:

class Person
  attr_reader :name, :age

  def initialize(name:, age:)
    @name = name
    @age = age
  end
end

你们知道实现我想要的任何解决方法吗?

感谢大家的帮助!

【问题讨论】:

  • 并不是说它一定更好,但我想指出,除了使用 instance_variable_set ...之外,还有一种不同的方法。你可以创建一个私有的 attr_reader
  • @maxpleaner 你能详细说明一下吗?
  • attr_reader :name + private :name。但这并不意味着它是不可变的。如果您希望它们不可变,您可以执行@name = name.freeze 和/或添加freeze 作为initialize 方法的最后一行,那么就无法更改任何实例变量。
  • 对不起,我的意思是私人 attr_writer ......但@KimmoLehto 是对的,我忘记了private 方法......你可以做attr_accessor :name; private :name=

标签: ruby


【解决方案1】:

你可以使用instance_variable_set,你不必依赖attr writer:

def initialize(data)
  data.each { |key, value| instance_variable_set("@#{key}", value) }
end

【讨论】:

    猜你喜欢
    • 2022-12-06
    • 2012-03-25
    • 2022-11-09
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2021-12-07
    • 2020-07-28
    相关资源
    最近更新 更多