简体   繁体   中英

undefined method … for class (NoMethodError)

I'm just startin to learn ruby and I'm writing a simple program, but I've got an error undefined method 'send_for_beer' for Person:Class (NoMethodError) Here is a code:

class Person
    @iq = 0
    @speed = 0
    @power = 0
    @beauty = 0
    def initialize (iq, speed, power, beauty)
        @iq = iq
        @speed = speed
        @power = power
    end

    def send_for_beer
        result @iq * 2 + @speed * 10 + @power * 5 + @beauty
        return result
    end
end

number_of_people = 3
person_array = Array.new(number_of_people, Person)
n = 0
beer_person = 0
beer_cof = 0
number_of_people.times do 

    ............
    person_array.push(Person.new(iq, speed, power, beauty))

    if person_array[n].send_for_beer > beer_cof     <-----here is an error
        beer_cof = person_array[n].send_for_beer
        beer_person = n
    end
    n = n+1
end

Here's your problem:

person_array = Array.new(number_of_people, Person)

In short, don't make array like this. Use the [] literal syntax. What this returns is:

[Person, Person, Person]

That is 3 references to the Person class, not instances. Then later you do:

person_array.push(Person.new(iq, speed, power, beauty))

And you end up with:

[Person, Person, Person, person_instance]

So when you iterate through and call send_for_beer on that first item, it does have that method because send_for_beer is an instance method that you are calling erroneously on a class object.

The fix here is to simply assign person_array to an empty array literal, and then push things to it.

person_array = []

And a minor style note: << is usually preferred to Array#push , making the filling of the array look more like this.

person_array << Person.new(iq, speed, power, beauty)

Ruby also support implicit return of the last expression in a method. So you do not need to return result . Instead, simply calulate the return value as the only line in the method.

def send_for_beer
  @iq * 2 + @speed * 10 + @power * 5 + @beauty
end

Instance variables don't quite work like that either. When you have @name in the class body directly, you are not initializing instance variables for each instance. You are actually setting instance variable on the class object (which is weird, I know). What you actually need to do is set them from any instance method, typically initialize , which you are doing here. So you can totally remove the instance variable setting at the class level here.

I think you've a syntax error in the method send_for_beer , the = sign is missing in the affectation of the variable result .

By the way, the method can be written

def send_for_beer
    @iq * 2 + @speed * 10 + @power * 5 + @beauty
end

If you have an array of fixed length, you can supply a block to create a new Person object for each element. You could rewrite your person_array line as follows:

person_array = Array.new(number_of_people) { Person.new(0, 0, 0, 0) }

Add the following line to the top of your class.

attr_writer(:iq, :speed, :power, :beauty)

This snipped of code could then modify the objects in your array.

person_array.each do |p|
    p.iq, p.speed, p.power, p.beauty = rand(20) + 1, rand(5) + 1, 1
    p.beauty = 10 if (rand(2) == 0)
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM