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

e = Example.new 
e.example_test 

Por supuesto, esto no va a funcionar, porque especificamos receptor explícita - caso del ejemplo (e), y que está en contra de una "regla privada".métodos Comprensión particulares en Rubí

pero no puedo entender, ¿por qué no se puede hacer en Ruby esto:

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

Foo.new.public_m 

El objeto actual en el interior public_m definición del método (es decir self) es la instancia de Foo. Entonces, ¿por qué no está permitido? Para arreglarlo tengo que cambiar self.private_m a solo private_m. Pero ¿por qué esto difiere, no es el self una instancia de Foo dentro de public_m? ¿Y quién es el receptor de la palabra desnuda private_m llamada? ¿No es eso self - lo que en realidad se omite porque, Ruby lo hará por usted (llamará private_m en sí mismo)?

Espero no haberlo confundido demasiado, todavía estoy fresco para Ruby.


EDIT: Gracias por todas las respuestas. Poniéndolos todos juntos pude (finalmente) asimilar lo obvio (y no tan obvio para alguien, que nunca había visto cosas como Ruby): ese self mismo puede ser receptor explícito e implícito y eso hace la diferencia. Entonces, hay dos reglas, si desea llamar a un método privado: self debe ser un receptor implícito, y ese auto debe ser una instancia de la clase actual (Example en ese caso, y eso tiene lugar solo cuando está dentro de la definición del método de instancia, durante esta ejecución del método). Por favor, corríjame si estoy equivocado.

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 

mensaje para cualquier persona que podría encontrar esta pregunta durante los senderos de Google: esto puede ser útil - http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

+0

[Aquí] (http://stackoverflow.com/questions/1565269/are-there-good-reasons-for-private-to -work-the-way-it-do-in-ruby) es una pregunta muy similar. – demas

Respuesta

46

Aquí está el corto y largo. Qué medios privados en Ruby es un método no se puede llamar con un receptor explícito, p. some_instance.private_method (value). Por lo tanto, aunque el receptor implícito sea uno mismo, en su ejemplo usted usa explícitamente el self para que los métodos privados no sean accesibles.

Piénselo de esta manera, ¿podría esperar llamar a un método privado utilizando una variable que ha asignado a una instancia de una clase? No. El yo es una variable, así que debe seguir las mismas reglas. Sin embargo, cuando acaba de llamar al método dentro de la instancia, funciona como se esperaba porque no está declarando explícitamente el receptor.

Rubí siendo lo que es en realidad se puede llamar a los métodos privados usando 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") } 

la esperanza de que es un poco más claro.

- editar -

Estoy asumiendo que sabía que esto funcionará:

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

Foo.new.public_m 
+0

Bueno, creo que lo entiendo ahora (o - Estoy mucho más cerca de entenderlo :) – Ernest

+4

Como usted cita la Sección 512, espero que sepa que bajo la misma subsección que permite los avisos de infracción, dicha notificación debe entregarse al agente designado para el negocio en cuestión. AFAIK, editar una respuesta en Stack Overflow no es un recurso previsto por la ley. Stack Overflow incluye una guía útil e información de contacto completa en su página Legal. (Nota de CYA: este comentario es improvisado, solo para valor informativo, y no debe interpretarse como consejo legal.) – Chuck

3

IIRC, métodos privados permiten única receptor implícita (que es siempre uno mismo, por supuesto).

13

Es raro, pero muchas cosas acerca de los modificadores de visibilidad de Ruby es extraña.Incluso si self es el receptor implícito, en realidad deletrearlo lo hace explícito a los ojos del tiempo de ejecución de Ruby. Cuando dice que los métodos privados no se pueden llamar con un receptor explícito, eso es lo que significa, incluso self cuenta.

+2

+1, ya que es fácil de recordar :) – Ernest

1

Lo siento por mi respuesta anterior. Simplemente no entiendo tu pregunta.

me cambió el código de la siguiente manera:

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 

Aquí es una llamada de método de instancia:

def public_m 
    private_m # <= 
end 

Éstos son una llamada de métodos de clase:

def Foo.static_m 
    puts "static" 
end 

def self.static2_m 
    puts "static 2" 
end 

Foo.static_m 
Foo.static2_m 
+0

Creo que se está perdiendo el sentido. Por lo que entiendo de su pregunta, él no entiende por qué usar self.private_m no funciona. Supongo que está acostumbrado a los idiomas que le permiten usar uno mismo o esto para llamar a métodos de instancia o usar variables de instancia. Creo que está confundido acerca de por qué el uso de Self lleva a cabo las obras, no cómo funcionan los accesorios privados y públicos. –

+0

@ Mike Bethany - es correcto – Ernest

+1

en lugar de crear respuestas múltiples, editar o ampliar su respuesta anterior. Eso nos ayuda a mantener las cosas en contexto. Gracias. –

17

El definición de private en Ruby es "solo puede ser cal led sin un receptor explícito ". Y es por eso que solo puedes llamar a métodos privados sin un receptor explícito. No hay otra explicacion.

Tenga en cuenta que en realidad hay una excepción a la regla: debido a la ambigüedad entre las variables locales y llamadas de método, se siempre ser resuelto lo siguiente para ser una asignación a una variable local:

foo = :bar 

Entonces, ¿qué haces si quieres llamar a un escritor llamado foo=? Bueno, usted tiene añadir un receptor explícito, ya que sin el receptor de Ruby simplemente no sabrá que desea llamar al método foo= en lugar de asignar a la variable local foo:

self.foo = :bar 

sino lo que haces hacer si desea llamar a un escritor private llamado foo=? Usted no puede escribirself.foo = porque foo= es private y por lo tanto no se puede llamar con un receptor explícito. Bueno, en realidad para este caso específico (y este caso solo ), que puede realidad utilizar un receptor explícito de self para llamar a un escritor private.

+1

Borra las dos primeras oraciones y tienes una gran respuesta. Deberías haber liderado con, "La definición de privado en Ruby es" solo se puede llamar sin un receptor explícito ". Y es por eso que solo puedes llamar a métodos privados sin un receptor explícito. No hay otra explicación". –

+0

Buena respuesta. Si estás aburrido, piensa en esto a través de: 'self.foo || = bar' –

+0

Gracias por mencionar la excepción de escritores. +1 incluso si no me siento cómodo con la respuesta que comienza con "así son las cosas ...". Saludos. – Ernest

0

No contesta exactamente la pregunta, pero se puede llamar a los métodos particulares de esta manera

class Example 
private 
def example_test 
    puts 'Hello' 
end 
end 

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

Adición de algunas mejoras a la solución de Gates usuario. Llamar a un método privado para el método de clase o un método de instancia es bastante posible. Aquí están los fragmentos de código. Pero no recomendado.

método de las clases

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

    private 
    def private_m 
    puts 'Hello' 
    end 
end 

e = Example.new.public_m 

Instancia Método

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

    private 
    def private_m 
    puts 'Hello' 
    end 
end 

e = Example.public_m 
Cuestiones relacionadas