2009-08-09 7 views
9

Cette méthode:Quand utiliser « auto » en Ruby

def format_stations_and_date 
    from_station.titelize! if from_station.respond_to?(:titleize!) 
    to_station.titleize! if to_station.respond_to?(:titleize!) 
    if date.respond_to?(:to_date) 
     date = date.to_date 
    end 
    end 

échoue avec cette erreur lorsque date est nul:

NoMethodError (You have a nil object when you didn't expect it! 
The error occurred while evaluating nil.to_date): 
    app/models/schedule.rb:87:in `format_stations_and_date' 
    app/controllers/schedules_controller.rb:15:in `show' 

Cependant, si je change date = date.to_date-self.date = self.date.to_date, la méthode fonctionne correctement .

Que se passe-t-il? En général, quand dois-je écrire self?

Modifier: Ce n'est pas lié à la question, mais s'il vous plaît noter qu'il n'y a pas de "titleize!" méthode.

+0

duplicata possible de [Pourquoi les monteurs de rubis ont-ils besoin de "soi"? qualification dans la classe?] (http://stackoverflow.com/questions/44715/why-do-ruby-setters-need-self-qualification-within-the-class) –

Répondre

42

Chaque fois que vous souhaitez appeler une méthode set sur self, vous devez écrire self.foo = bar. Si vous écrivez simplement foo = bar, l'analyseur ruby ​​reconnaît cela comme une affectation de variable et considère désormais foo comme une variable locale. Pour que l'analyseur réalise que vous voulez invoquer une méthode setter et que vous n'attribuez pas de variable locale, vous devez écrire obj.foo = bar, donc si l'objet est self, self.foo = bar

7

Vous désambiguez entre le nom de la méthode d'instance et une variable locale utilisant self (il est permis d'avoir les deux avec le même nom dans la même portée). En d'autres termes, il y aura une résolution de nom de méthode seulement s'il n'y a pas de variable locale ou de bloc du même nom dans la portée. Voici:

class Foo 
    attr_accessor :boo 
    def do_boo 
    boo = 123 
    puts "Locvar: #{boo} Method: #{self.boo}" 
    end 
end 
Foo.new.do_boo 

Voici pourquoi: imaginez que vous avez un module qui implémente une méthode. Cette méthode assigne quelque chose à sa variable locale interne "foo" qui est utilisée pour certains calculs. Si vous sautez la partie "self", la méthode fera un appel de méthode "foo =" sur l'objet dont la classe inclut le module, ce qui n'était pas l'intention de l'auteur et peut être carrément désastreux.

class Foo 
    def bar=(new_value_of_bar) 
    set_off_nukes(new_value_of_bar/3) 
    end 
end 

module InnocentModule # written by a different author elsewhere 
    def do_useful_stuff 
    ... 
    bar = Math.sin(something) # we're dead 
    end 
end 
Foo.send(:include, InnocentModule) 

Une autre partie cruciale où vous devez utiliser l'auto est l'objet lors de l'appel de méthode # classe, parce que tout simplement dire « classe » signifie un mot-clé de classe pour Ruby.

Questions connexes