首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用于`my_attr=( #<My_class:0x000001>,NoMethodError)的未定义方法NoMethodError

用于`my_attr=( #<My_class:0x000001>,NoMethodError)的未定义方法NoMethodError
EN

Stack Overflow用户
提问于 2019-05-18 16:55:19
回答 2查看 158关注 0票数 0

我正在Person.rb文件中创建一个新的Person类。当我在终端中使用ruby Person.rb时,它显示了一个NoMethodError:

代码语言:javascript
运行
复制
Person.rb:12:in `<main>': undefined method `name=' for #<Person:0x00000001abb6d8> (NoMethodError)
Did you mean?  name

这就是我写的代码:

代码语言:javascript
运行
复制
class Person
    attr :name, :age, :gender
end

person = Person.new

person.name = "John"
person.age = 55
person.gender = "male"

puts(person.name, person.age, person.gender)

有什么建议吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-18 18:11:36

如果您查看Module#attr,您将看到使用它有三个“重载”:

attr(name, …)nil attr(name, true)nil attr(name, false)nil

然后,这些文件进一步解释了三者之间的区别:

第一种形式等价于attr_reader。第二种形式等价于attr_accessor(name),但不推荐使用。最后一个表单等价于attr_reader(name),但不推荐使用。

因此,第一和第三种形式只产生读者,而不是作家。第二个表单生成一个读取器和一个编写器,但是它只接受一个name形式参数,您不能使用它来生成多个属性。

另外,表格二和表格三被否决,所有这三种形式都是非惯用的.

如果要使用非惯用的Module#attr修复代码,则需要这样做:

代码语言:javascript
运行
复制
attr :name  , true
attr :age   , true
attr :gender, true

您可以使用以下的方法来简化这一点

代码语言:javascript
运行
复制
%i[name age gender].each do |attribute|
  attr attribute, true
end

但是,正如文档中所提到的,这个表单是不可取的,正如我前面提到的,Module#attr是非惯用的。

惯用的方法是使用Module#attr_*族的方法,即Module#attr_readerModule#attr_writerModule#attr_accessor

代码语言:javascript
运行
复制
attr_accessor :name, :age, :gender

注意,由于您的Person类实际上没有任何行为,所以您可以简单地用一个Struct替换它

代码语言:javascript
运行
复制
Person = Struct.new(:name, :age, :gender)

但是,请注意,访问器,特别是编写器,并不是好的面向对象设计。对象应该做些什么,它们应该有行为。您的Person对象没有任何行为,它们只包含数据。此外,一个对象在创建之后应该是有效的,但是您的Person对象在创建时是空的。最后,如果可能的话,对象应该是不可变的。

我们可以通过添加初始化程序来确保创建后的对象是有效的:

代码语言:javascript
运行
复制
class Person
  attr_accessor :name, :age, :gender

  def initialize(name, age, gender)
    self.name, self.age, self.gender = name, age, gender
  end
end

person = Person.new('John', 55, 'male')

注意:Struct将为我们创建一个初始化器。

如果要使对象不可变,则需要删除写入器(或使其为private)。不幸的是,Struct不会为我们这样做:

代码语言:javascript
运行
复制
class Person
  attr_reader :name, :age, :gender

  private

  attr_writer :name, :age, :gender

  def initialize(name, age, gender)
    self.name, self.age, self.gender = name, age, gender
  end
end

person = Person.new('John', 55, 'male')

现在,person在创建它之后已经完全初始化,并且它不能再被更改了。

票数 0
EN

Stack Overflow用户

发布于 2019-05-18 17:16:15

您需要做的一些修改:

请在您的红宝石类中使用attr_accessor :name, :age, :gender

然后试着:

代码语言:javascript
运行
复制
 puts person.name
 puts person.age
 puts person.gender

它应该对你有用..。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56201052

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档