2010-11-27 4 views
45
class Example 
private 
def example_test 
    puts 'Hello' 
end 
end 

e = Example.new 
e.example_test 

Bien sûr, ne fonctionnera pas, parce que nous avons spécifié récepteur explicite - par exemple de l'exemple (e), et qui est contre une « règle privée ».Comprendre les méthodes privées dans Ruby

Mais je ne comprends pas, pourquoi on ne peut pas faire en Ruby ceci:

class Foo 
def public_m 
    self.private_m # <= 
end 
private 
def private_m 
    puts 'Hello' 
end 
end 

Foo.new.public_m 

L'objet courant à l'intérieur public_m définition de la méthode (à savoir self) est l'instance de Foo. Alors pourquoi est-ce interdit? Pour corriger cela, je dois changer self.private_m juste private_m. Mais pourquoi cela diffère, n'est pas le self une instance de Foo à l'intérieur public_m? Et qui est le destinataire de l'appel private_m nu-mot? N'est-ce pas self - qu'est-ce que vous omettez réellement parce que, Ruby le fera pour vous (appellera private_m on self)?

J'espère ne pas trop le confondre, je suis encore fraîche à Ruby.


EDIT: Merci pour toutes les réponses. En les mettant tous ensemble, j'ai pu (enfin) grok l'évidence (et pas si évident pour quelqu'un, qui n'a jamais vu des choses comme Ruby): que self lui-même peut être récepteur explicite et implicite et qui font la différence. Donc il y a deux règles, si vous voulez appeler une méthode privée: self doit être un récepteur implicite, et ce self doit être une instance de la classe actuelle (Example dans ce cas) et cela n'a lieu que si self si dans la définition de méthode d'instance, pendant l'exécution de cette méthode). S'il vous plait corrigez moi si je me trompe.

class Example 

# self as an explicit receiver (will throw an error) 
def explicit 
    self.some_private_method 
end 

# self as an implicit receiver (will be ok) 
def implicit 
    some_private_method 
end 

private 

def some_private_method; end 
end 

Example.new.implicit 

Message pour tous ceux qui pourraient trouver cette question au cours des pistes Google: cela peut être utile - http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

+0

[ici] (http://stackoverflow.com/questions/1565269/are-there-good-reasons-for-private-to -work-the-way-it-does-in-ruby) est une question très similaire. – demas

Répondre

46

Voici le court et le long de celui-ci. Quel moyen privé dans Ruby est une méthode ne peut pas être appelée avec un récepteur explicite, par ex. some_instance.private_method (valeur). Ainsi, même si le récepteur implicite est self, dans votre exemple, vous utilisez explicitement self pour que les méthodes privées ne soient pas accessibles. Pensez-y de cette façon, vous attendriez-vous à pouvoir appeler une méthode privée en utilisant une variable que vous avez assignée à une instance d'une classe? Non. Self est une variable qui doit donc suivre les mêmes règles. Toutefois, lorsque vous appelez simplement la méthode dans l'instance, cela fonctionne comme prévu car vous ne déclarez pas explicitement le destinataire.

Ruby étant ce qu'elle est que vous pouvez réellement appeler les méthodes privées utilisant instance_eval:

class Foo 
    private 
    def bar(value) 
    puts "value = #{value}" 
    end 
end 

f = Foo.new 
begin 
    f.bar("This won't work") 
rescue Exception=>e 
    puts "That didn't work: #{e}" 
end 
f.instance_eval{ bar("But this does") } 

Espoir qui est un peu plus clair.

- modifier -

Je suppose que vous saviez que cela fonctionne:

class Foo 
def public_m 
    private_m # Removed self. 
end 
private 
def private_m 
    puts 'Hello' 
end 
end 

Foo.new.public_m 
+0

Eh bien, je pense que je comprends maintenant (ou - je suis beaucoup plus près de le comprendre :) – Ernest

+4

Depuis que vous citez la section 512, j'espère que vous êtes conscient que sous le même paragraphe qui permet les avis de violation, un tel avis doit être délivré à l'agent désigné pour l'entreprise en question. AFAIK, éditer une réponse sur Stack Overflow n'est pas un recours prévu par la loi. Stack Overflow inclut un guide utile et toutes les informations de contact sur sa page juridique. (Note de l'ACY: Ce commentaire est spontané, à titre informatif seulement, et ne devrait pas être interprété comme un avis juridique.) – Chuck

3

IIRC, des méthodes privées permettent ne récepteur implicite (ce qui est toujours soi-même, bien sûr).

13

Il est bizarre, mais beaucoup de choses sur les modificateurs de visibilité de Ruby sont bizarres.Même si self est le récepteur implicite, l'orthographier le rend explicite aux yeux de Ruby Runtime. Quand il dit que les méthodes privées ne peuvent pas être appelées avec un récepteur explicite, c'est ce que cela signifie, même self compte.

+2

+1, car c'est facile à retenir :) – Ernest

1

Désolé pour ma réponse précédente. Je ne comprends tout simplement pas votre question.

j'ai changé votre code comme ceci:

class Foo 
def public_m 
    private_m # <= 
end 

def Foo.static_m 
    puts "static" 
end 

def self.static2_m 
    puts "static 2" 
end 

private 
def private_m 
    puts 'Hello' 
end 
end 

Foo.new.public_m 
Foo.static_m 
Foo.static2_m 

Voici un appel de méthode d'instance:

def public_m 
    private_m # <= 
end 

Voici un appel de méthodes de classe:

def Foo.static_m 
    puts "static" 
end 

def self.static2_m 
    puts "static 2" 
end 

Foo.static_m 
Foo.static2_m 
+0

Je pense que vous avez manqué le point. D'après ce que je comprends de sa question, il ne comprend pas pourquoi utiliser self.private_m ne fonctionne pas. Je suppose qu'il est habitué aux langages qui vous permettent d'utiliser self ou this pour appeler des méthodes d'instance ou utiliser des variables d'instance. Je pense qu'il est confus au sujet de pourquoi l'utilisation de Self est en train de perdre les travaux, pas comment les accesseurs privés et publics fonctionnent. –

+0

@ Mike Bethany - c'est exact – Ernest

+1

plutôt que de créer plusieurs réponses, modifier ou étendre votre réponse précédente. Cela nous aide à garder les choses dans leur contexte. Merci. –

17

Le définition de private dans Ruby est "peut seulement être cal conduit sans récepteur explicite ". Et c'est pourquoi vous ne pouvez appeler des méthodes privées sans récepteur explicite. Il n'y a pas d'autre explication.

Notez qu'il existe en fait une exception à la règle: en raison de l'ambiguïté entre les variables locales et les appels de méthode, ce qui suit toujours être résolu d'être une affectation à une variable locale:

foo = :bar 

Alors, que faites-vous si vous voulez appeler un écrivain appelé foo=? Eh bien, vous avez d'ajouter un récepteur explicite, car sans le récepteur Ruby tout simplement pas savoir que vous voulez appeler la méthode foo= au lieu d'attribuer à la variable locale foo:

self.foo = :bar 

Mais qu'est-ce que vous faire si vous voulez appeler un écrivain private appelé foo=? Vous ne peut pas écrire self.foo = car foo= est private et ne peut donc pas être appelé avec un récepteur explicite. Eh bien, en fait pour ce cas particulier (et ce cas seul), vous pouvez réellement utiliser un récepteur explicite de self d'appeler un écrivain private.

+1

Effacer les deux premières phrases et vous avez une bonne réponse. "La définition de private dans Ruby est" ne peut être appelée que sans récepteur explicite ", et c'est pourquoi vous ne pouvez appeler des méthodes privées sans récepteur explicite, il n'y a pas d'autre explication." –

+0

Bonne réponse. Si vous vous ennuyez un certain temps, pensez à celui-ci à travers: 'self.foo || = bar' –

+0

Merci d'avoir mentionné l'exception des auteurs. +1 même si je ne me sens pas à l'aise avec une réponse qui commence par «c'est comme ça ..». Cordialement. – Ernest

0

ne répond pas exactement à la question, mais vous pouvez appeler des méthodes privées de cette façon

class Example 
private 
def example_test 
    puts 'Hello' 
end 
end 

e = Example.new 
e.send(:example_test) 
1

L'ajout de quelques améliorations à la solution Gates utilisateur. L'appel d'une méthode privée à la méthode class ou à une méthode d'instance est pratiquement possible. Voici les extraits de code. Mais pas recommandé.

Méthode classe

class Example 
    def public_m 
    Example.new.send(:private_m) 
    end 

    private 
    def private_m 
    puts 'Hello' 
    end 
end 

e = Example.new.public_m 

instance Méthode

class Example 
    def self.public_m 
    Example.new.send(:private_m) 
    end 

    private 
    def private_m 
    puts 'Hello' 
    end 
end 

e = Example.public_m 
Questions connexes