неопределенный метод `my_attr = 'для #(NoMethodError) - PullRequest
0 голосов
/ 18 мая 2019

Я создаю новый класс Person в файле Person.rb. Когда я использую ruby Person.rb в моем терминале, он показывает NoMethodError:

Person.rb:12:in `<main>': undefined method `name=' for #<Person:0x00000001abb6d8> (NoMethodError)
Did you mean?  name

это код, который я написал:

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)

есть предложения?

Ответы [ 2 ]

0 голосов
/ 18 мая 2019

Если вы посмотрите на документацию Module#attr, вы увидите, что есть три "перегрузки" для его использования:

attr(name, …)nil

attr(name, true)nil

attr(name, false)nil

Затем в документации дополнительно объясняются различия между ними:

Первая форма эквивалентна attr_reader. Вторая форма эквивалентна attr_accessor(name), но устарела. Последняя форма эквивалентна attr_reader(name), но устарела.

Итак, первая и третья формы порождают только читателей, а не писателей. Вторая форма генерирует читателя и писателя, но она принимает только один name формальный параметр, вы не можете использовать его для создания нескольких атрибутов.

Кроме того, формы две и три устарели, и все три формы не являются идиоматическими.

Если вы хотите исправить свой код, используя не-идиоматический Module#attr, вам нужно сделать это:

attr :name  , true
attr :age   , true
attr :gender, true

Вы можете немного упростить это, используя что-то вроде

%i[name age gender].each do |attribute|
  attr attribute, true
end

Однако, как упоминалось в документации, эта форма устарела, и, как я упоминал ранее, Module#attr не является идиоматическим.

Идиоматическим способом является использование семейства методов Module#attr_*, то есть Module#attr_reader, Module#attr_writer и Module#attr_accessor:

attr_accessor :name, :age, :gender

Обратите внимание, что поскольку ваш класс Person фактически не имеет никакого поведения, вы можете просто заменить его на Struct:

Person = Struct.new(:name, :age, :gender)

Однако обратите внимание, что средства доступа вообще и авторы в частности не являются хорошим объектно-ориентированным проектом. Объекты должны делать что-то, они должны иметь поведение . Ваши Person объекты не имеют никакого поведения, они просто содержат данные. Кроме того, объект должен быть действительным после его создания, но ваши объекты Person будут пустыми при их создании. И наконец, если это вообще возможно, объекты должны быть неизменными .

Мы можем убедиться, что объект действителен после создания, добавив инициализатор:

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 не сделает это для нас:

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 голосов
/ 18 мая 2019

Некоторые изменения, которые вам нужно сделать:

, пожалуйста, используйте attr_accessor :name, :age, :gender в вашем классе рубина

и затем попробуйте:

 puts person.name
 puts person.age
 puts person.gender

Это должно работать для вас..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...