1
votes

Comment Ruby fait-il la différence entre la méthode d'instance et la définition de méthode de classe?

Dans le code ruby ​​normal, je peux normalement omettre self:

# 1
class User
  def self.greeting
    # ...
  end
end

# 2
class User
  def greeting
    # ...
  end
end

mais pourquoi ces 2 sont-ils différents:

class User
  def greeting
    # these 2 are the same:
    puts "Hi, #{name}"
    puts "Hi, #{self.name}"
  end
end


2 commentaires

Votre question n'est pas claire. En quoi le n ° 1 est-il différent du n ° 2? ils ne sont pas.


Désolé, j'ai oublié de me supprimer dans # 2


6 Réponses :


0
votes

Dans une classe, si vous définissez une méthode sur soi, il la définit sur la classe. Par exemple,

user = User.new
user.greeting
# => "Hello user"

Ensuite, vous pouvez appeler

class User
  def greeting
    "Hello user"
  end
end

Si vous définissez une méthode sans self, alors cette méthode est définie pour les objets de cette classe. Par exemple:

User.greeting
# => "Hello User"

Ensuite, vous devez créer un nouvel objet utilisateur pour appeler greeting.

class User
  def self.greeting
    "Hello User"
  end
end


1 commentaires

Je le sais mais je ne sais pas pourquoi ça marche comme ça. Je voudrais comprendre comment ruby ​​gère le contexte et le moi et arriver à cette différence



3
votes

Le self est parfois nécessaire (sinon il n'existerait pas du tout). Le premier exemple que vous donnez est un cas où il est redondant. Ces deux appels de méthode font référence à la même méthode.

Il y a des moments où il est nécessaire de faire la distinction entre deux comportements différents.

Dans vos exemples n ° 1 et n ° 2 le self est utilisé pour s'assurer que la méthode est définie sur la classe, plutôt que sur des instances de la classe. Le self n'est pas redondant dans ce cas. C'est ainsi que l'interpréteur Ruby sait où vous voulez que la méthode soit définie. Il peut être utile de penser au self dans votre tout premier exemple comme une chose différente du self dans les exemples # 1 et # 2. Il pourrait être utile de considérer le self dans les # 1 et # 2 comme " classe "? Il s'agit du même mot-clé, mais la manière dont ils sont utilisés n'est pas directement interchangeable.

Un autre exemple où il n'est pas redondant:

# user.rb

def method1
  name = "Henry" # Sets a local variable called `name`
end

def method2
  self.name = "Henry" # Sets the user's `name` attribute
end


1 commentaires

J'ai mis à jour ma réponse en fonction de vos autres commentaires et du changement de titre. Plus précisément cette partie: il peut être utile de penser au self dans votre tout premier exemple comme une chose différente du self dans les exemples # 1 et # 2. Il pourrait être utile de considérer le self dans les # 1 et # 2 comme une classe ? C'est le même mot, mais ce à quoi ils servent et le changement n'est pas directement interchangeable.



4
votes

Dans un corps de méthode , self fait référence au récepteur . Dans les lignes 3 à 4 de ce qui suit, une fois que le récepteur est déterminé comme étant une instance User (par la syntaxe def greeting ), self fait référence à cette instance.

def User.greeting; ... end
def greeting; ... end

Dans un corps de classe , self fait référence à la classe . Dans les lignes 2, 4, 8, 10 de ce qui suit, la classe est User , donc def self.greeting est identique à def User.greeting code>.

name
self.name

Mais je pense en fait que votre véritable problème n'est pas ce que signifie self , mais plutôt ce que signifie «un récepteur omis» , dans différents contextes.

Dans la syntaxe méthode- appelant , un récepteur omis signifie self . Donc, les deux suivants sont identiques:

class User
  def self.greeting # class body
    # ...
  end               # class body
end

class User
  def greeting      # class body
    # ...
  end               # class body
end

Dans la syntaxe de la définition de méthode , un récepteur omis signifie "toute instance de la classe". Donc, les deux suivants ne sont pas les mêmes:

class User
  def greeting
    puts "Hi, #{name}"      # method body
    puts "Hi, #{self.name}" # method body
  end
end

Lorsque vous définissez une méthode d'instance, il n'y a pas de moyen explicite d'exprimer "n'importe quelle instance de la classe", donc en fait obligatoire.


0 commentaires

0
votes

self est obligatoire lors de la définition des méthodes de classe, alors que sans le mot-clé self, il sera traité comme des méthodes d'instance. classe << self; end; bloc également utilisé pour définir le nombre de méthodes de classe.

Ces méthodes sont chargées lorsque votre classe est chargée et ci-dessus aidera à les distinguer.

Ce sera simplement comme une relation avec un exemple réel .

Vous avez un certain nombre de comptes ayant une authentification fournie sur votre ordinateur, une personne valide avec le bon mot de passe peut entrer dans le compte. Une fois que vous entrez dans le compte interne, vous n'avez pas besoin de mentionner qui vous êtes! C'est toujours vous qui êtes entré.


0 commentaires

1
votes

Les méthodes définies sur une classe sont des méthodes d'instance :

class Animal
  class << self
    def pig(n)
      "#{n} little pigs"
    end
  end
end

Elles sont ainsi nommées car elles répondent à n'importe quelle instance de la classe, ce qui signifie que leur récepteur doit être une instance de la classe:

class Animal
  def self.pig(n)
    "#{n} little pigs"
  end
end

Pour définir une méthode dont le récepteur est une classe (une méthode de classe ) nous définissons la méthode sur la classe classe singleton. Pour la classe Animal , nous pourrions écrire l'un des éléments suivants.

class Animal
  def Animal.pig(n)
    "#{n} little pigs"
  end
end

ou

str = "cow"
str.define_singleton_method(:greeting) { "moo" }
str.greeting
  #=> "moo"

arr = [1,2]
arr.define_singleton_method(:greeting) { "I'm an array" }
arr.greeting
  #=> "I'm an array"

module M; end
M.define_singleton_method(:greeting) { "I'm a module" }
M.greeting
  #=> "I'm a module"

piggy = Animal.method(:pig)
  #=> #<Method: Animal.pig> 
piggy.define_singleton_method(:greeting) { 
  "I'm a singleton method" }
piggy.greeting
  #=> "I'm a singleton method"

La ligne class 1 change la portée en la classe singleton de Animal , provoquant la valeur de self à changer pour cette classe également.

Alors qu'est-ce que cela a à voir avec la question, c'est-à-dire définir les méthodes def self.my_method ... ? La réponse courte est qu'il n'est pas nécessaire de définir des méthodes de cette manière. Soyez patient, j'y reviendrai.

Notez que la méthode pig , définie sur la classe singleton de Animal , est héritée par la classe singleton des sous-classes de Animal code>:

Animal.new.rodent(55)
  #=> #NoMethodError (undefined method `rodent' for
  #     #<Animal:0x00005bfb0c530670>)

Nous pouvons également définir des méthodes sur de nombreux objets uniques . Considérez animal , une instance de Animal:

animal.define_singleton_method(:rodent) do |n|
  "I'm rodent ##{n}"
end

animal.rodent(3241)
  #=> "I'm rodent #3241"

animal est le seul récepteur à à laquelle cette méthode répondra:

class Swine < Animal
end

Swine.instance_methods & [:dog, :cat]
  #=> [:dog, :cat]
Swine.methods & [:pig]
  #=> [:pig] 

En fait, nous pouvons définir des méthodes sur chaque objet qui a une classe singleton, qui est la plupart des objets:

Animal.define_singleton_method(:pig) do |n|
  "#{n} little pigs"
end

Animal.methods(false)
  #=> [:pig] 
Animal.pig(3)
  #=> "3 little pigs"

Nous pouvons faire cela avec tous les objets Ruby qui ont une classe singleton. Cela comprend tous les objets sauf ceux ayant des valeurs immédiates (objets passés par valeur), qui incluent nil , true , false code >, Des nombres entiers, des symboles et des flottants. De plus, les objets qui ont été gelés (par exemple, "Hi" .freeze ) n'ont pas de classe singleton.

Supposons maintenant que nous écrivions

class Animal
  class << Animal
    def pig(n)
      "#{n} little pigs"
    end
  end
end

Animal.methods(false)
  #=> [:pig] 
Animal.pig(3)
  #=> "3 little pigs"

ou (même chose)

Animal.instance_methods(false)
  #=> [:dog, :cat] 
animal = Animal.new
  #=> #<Animal:0x00005bfb0c55ae98>  
animal.dog
  #=> "woof"
Animal.dog
  #=> NoMethodError (undefined method `dog' for Animal:Class)

(On y est enfin!)

Quelle est cette nouvelle façon de définir un méthode? C'est en fait juste une manière abrégée de définir une méthode sur la classe singleton de Animal . Considérez-le simplement comme un sucre syntaxique . Tout comme l'écriture de 2 + 2 demande à Ruby d'exécuter 2. + (2) , Animal. ou self. dans la première ligne de la définition de méthode indique simplement à Ruby d'exécuter ce qui suit.

class Animal
  def dog
    "woof"
  end

  def cat
    "meow"
  end
end

En d'autres termes, la création d'une méthode de classe en écrivant def Animal.my_method. .. ou def self.my_method ... n'est pas du tout nécessaire; c'est là simplement pour des raisons de commodité pour les codeurs Ruby.

1 Cette ligne serait généralement écrite class , ce qui est acceptable comme self code> vaut Animal lorsque la ligne est exécutée. Utiliser est simplement une commodité si la classe est renommée.


0 commentaires

0
votes

Tout d'abord, il est important de comprendre qu'il n'y a pas de méthode de classe ou de méthode singleton dans Ruby. Il n'y a qu'un seul type de méthode: les méthodes d'instance.

La vraie question est: dans quel module la méthode est-elle définie?

[ «Méthode singleton» et «méthode de classe» sont simplement des noms abrégés que nous utilisons pour «méthode définie dans la classe singleton» et «méthode définie dans la classe singleton d'un objet dont la classe est Class code > ".]

Il existe deux formes de définitions de méthodes dans Ruby:

class Foo
  def self.foo; end
end

et

class Foo
  p self
end

Le premier évaluera d'abord l'expression some_expression puis définira une méthode nommée some_name dans la classe singleton de l'objet résultant. p>

La seconde définira une méthode nommée some_name dans ce que l'on appelle le default definee . La définition par défaut est généralement la définition de module englobant lexicalement la plus proche . Par exemple, dans ce cas:

def foo; end

Ici, bar sera défini comme une méthode d'instance de Foo :: Bar code >, car bar est la définition de module englobant lexicalement la plus proche. Il existe une autre définition lexicale encore plus proche, à savoir la définition de méthode de foo , mais ce n'est pas une définition de module.

Un peu plus déroutant:

XXX

Cela définira foo comme une méthode d'instance de Foo , même si techniquement ce n'est pas un module définition, c'est "juste" un bloc. Cependant, c'est pourquoi j'ai écrit "généralement" ci-dessus: certaines méthodes peuvent changer le paramètre par défaut, et Class :: new est l'une de ces méthodes (similaire à comment, par exemple Object # instance_eval code> change la valeur de self).

Autre exemple:

Foo = Class.new do
  def foo; end
end

Dans ce cas, il y a aucune définition de module englobant lexicalement. Au plus haut niveau, la définition par défaut est Object mais avec une torsion: la visibilité par défaut est également private.

Tout cela est expliqué dans plus de détails dans le brillant article de blog Trois contextes implicites dans Ruby par yugui.

Maintenant, la seule chose qui manque est: qu'est-ce que l'expression self évalue à l'intérieur d'une définition de module? Eh bien, vous pouvez le tester si vous le souhaitez:

module Foo
  module Bar
    def foo
      def bar; end
    end
  end
end

include Foo::Bar

foo
# At this point, `bar` will be defined, but where?

La réponse est que dans une définition de module, self évalue le module en cours de définition. (Ça a du sens, n'est-ce pas?)

Par conséquent, dans

def some_name; end

toto est défini dans la classe singleton de Foo.


0 commentaires