2012-07-24 10 views
6

En Ruby, entiendo que self es el receptor implícito para cualquier llamada al método bare. Sin embargo:Si `self` es siempre el receptor implícito en Ruby, ¿por qué` `self.puts` no funciona?

~: irb 
>> puts "foo" 
foo 
=> nil 
>> self.puts "foo" 
NoMethodError: private method `puts' called for main:Object 

¿Qué explica esto?

En caso de que alguna ayuda:

>> method(:puts).owner 
=> Kernel 
+1

try 'self.send: puts," foo "'. Puedes moverte por métodos privados con send. – DGM

Respuesta

8

Los métodos privados no pueden tener un receptor

Creo que la respuesta es la siguiente: manera de hacer cumplir la privacidad método de Ruby es que no permite llamar a los métodos privados con un receptor explícito.

Un ejemplo:

class Baker 
    def bake_cake 
    make_batter 
    self.use_oven # will explode: called with explicit receiver 'self' 
    end 

    private 
    def make_batter 
    puts "making batter!" 
    end 

    def use_oven 
    puts "using oven!" 
    end 

end 

b = Baker.new 
b.bake_cake 

Como no puede haber ningún receptor explícita, que sin duda no puede hacer b.use_oven. Y así es como se aplica la privacidad del método.

+0

pero puts es un método público, método (: puts) .owner.public_methods.grep/puts/returns [: puts]. MRI ruby ​​1.93p194 – dfang

+0

lo siento, olvidé la búsqueda de métodos. auto.class.ancestors => [Object, Kernel, BasicObject] – dfang

+0

@dfang - ¿tal vez una clase infantil lo reclasifique como privado? –

3

Usted es correcto que self es el receptor implícita cuando no se especifica una forma explícita. La razón por la que no está permitido hacer self.puts es que no puede llamar a métodos privados con un receptor explícito (incluso si ese receptor es self) y como dice el mensaje de error, puts es un método privado.

1

No se puede acceder a métodos privados en ruby ​​usando la sintaxis self., o en general usando cualquier receptor (algo delante del .). Eso solo es posible para los métodos protegidos.

4

Porque esa es la definición de privacidad en Ruby: los métodos privados solo se pueden invocar con un receptor implícito.

En realidad, hay una excepción a esta regla: porque foo = barsiempre crea una variable local, se le permite llamar a los emisores privados como self.foo = bar, porque de lo contrario no sería capaz de llamarlos en absoluto (sin usando la reflexión).

+1

+1 por mostrar la excepción. –

+0

Además de usar la reflexión, puede hacer 'foo = (bar)' sin usar 'self'. –

+1

@AndrewGrimm: no funciona, solo lo probé. También tiene sentido que no funcione, porque los paréntesis se pueden usar para agrupar expresiones, por lo que es una asignación de variables locales perfectamente válida. –

Cuestiones relacionadas