2009-12-19 6 views
6

En Ruby, se supone que todo es un objeto. Pero tengo un gran problema para llegar al objeto de función definida de la forma habitual, comoObtener el objeto de función ruby ​​en sí

def f 
    "foo" 
end 

diferencia en Python, F es el resultado de la función, no la propia función. Por lo tanto, f(), f, ObjectSpace.f son todos "foo". También f.methods devuelve solo la lista de métodos de cadena.

¿Cómo accedo al objeto de la función en sí?

+0

Esta es una de (muchas) cosas que me vuelven loco en ruby. No puede hacer referencia a una función por nombre sin invocarla. Tengo argumentos sobre esto con mis orkers de vacas. –

+0

Creo que Ruby tiene su propio camino y algunos principios utilizados en otros idiomas simplemente no se aplican (en este caso, probablemente definiría la función con Proc, o usaría el bloque de código), pero aún me pregunto si hay una respuesta positiva a mi pregunta – mykhal

+1

@Jonathan: Puede referirse al nombre de un método sin llamarlo. El nombre de un método es un símbolo. Entonces el nombre de este método es ': f'. Ruby es bastante famoso por sus capacidades de metaprogramación, y los nombres de los métodos se usan todo el tiempo allí. – Chuck

Respuesta

10

Simplemente use el método method. Esto devolverá la instancia Method que coincida con ese método. Algunos ejemplos:

>> def f 
>> "foo" 
>> end 
=> nil 
>> f 
=> "foo" 
>> method(:f) 
=> #<Method: Object#f> 
>> method(:f).methods 
=> [:==, :eql?, :hash, :clone, :call, :[], ...] 
>> class SomeClass 
>> def f 
>>  "bar" 
>> end 
>> end 
=> nil 
>> obj = SomeClass.new 
=> #<SomeClass:0x00000001ef3b30> 
>> obj.method(:f) 
=> #<Method: SomeClass#f> 
>> obj.method(:f).methods 
=> [:==, :eql?, :hash, :clone, :call, :[], ...] 

Espero que esto ayude.

+0

Oh, y el objeto Method es un objeto similar al de Proc, por lo que doo 'obj.method (: f) .call()' o 'obj.method (: f) []' para llamar eso. O bien, en Ruby 1.9.1; 'obj.method (: f).()'. – henrikhodne

0

Puede obtener un objeto que corresponda a esa función en el tiempo de ejecución, pero hasta donde yo sé no hay equivalente a lo que Python le permite hacer allí mismo en la definición de la función/clase.

Esperemos que alguien me demuestre que estoy equivocado, pero nunca he sido capaz de llevarlo a cabo.

1

En Ruby, lo que está pidiendo no tiene sentido. (Tiene sentido en lenguajes como Python, JavaScript, Java y C#.)

En Ruby, puede decirle a una clase a qué mensajes debe responder y de qué manera debe responder a esos mensajes. La forma más común de decirle a una clase que debe definir un método en la clase. Pero, nuevamente, eso simplemente significa: cuando alguien envía el mensaje f a esta instancia, este es el comportamiento con el que la instancia debe responder. No hay objeto de función.

Puede hacer cosas como obtener un símbolo (method_name = :foo) y obtener un cierre (method = proc { obj.foo }).

+0

si f no es un objeto, ¿por qué está en ObjectSpace? – mykhal

+0

Los métodos son objetos. Simplemente no son objetos a los que el tiempo de ejecución le permite acceder MIENTRAS aún se están definiendo. Si quieres hacer eso, entonces quédate con Python. –

+0

En realidad, hay una clase de Método que todos los métodos son una instancia de. Cuando haces 'obj.some_method' en Ruby, envía el mensaje a obj, que busca en su lista de métodos un método de coincidencia, y luego llama a ese método. Si no puede encontrar el método, llama 'method_missing'. – henrikhodne

1

Esa no es una función; es un método de un objeto. Si desea obtener un objeto que representa un método, usted le pide al objeto propietario para ello:

someobj.method :f 

Por ejemplo:

plus_one = 1.method :+ 
plus_one[9] # 10 
+0

'def f; "foo"; fin' realmente no es una función? – mykhal

+0

Conceptualmente, no, es un método. Está intrínsecamente vinculado a un propietario en Ruby. El equivalente de Ruby más cercano a las funciones verdaderas sería Procs. – Chuck

3

El método method le dará un objeto Method

f = obj.method :f 
puts f.call # or f[] 

este f está destinado a obj. También puede obtener un método no unido:

unbound_plus = Fixnum.instance_method('+') 
plus_2 = unbound_plus.bind(2) 

(También hay un método unbind)

+0

por lo que diría que mi f es el método independiente. parece razonable. sin embargo, el hecho de que mis amigos actúen como métodos ObjectSpace (que devuelven los objetos) confunde bien – mykhal

+0

, todavía no responde mi pregunta, ¿cómo trato mi f como instancia de método – mykhal

+0

@mykhal: cualquier método que defina en el nivel superior se convierte en un método de instancia de Object, por lo que ObjectSpace (que es un objeto, al igual que todo lo demás en el lenguaje) obtiene el método también. Sin embargo, normalmente no debería poder llamar desde fuera de ObjectSpace, ya que los métodos definidos de esa manera son privados por defecto. – Chuck

2

así he encontrado la respuesta a mí mismo

obj = method :f 

gracias a todos por la inspiración :)

+0

Esto le proporciona el método, pero no una función pura. Crear un objeto 'Proc' es tal vez más cercano a lo que desea. Un método siempre requiere un receptor, ya que está vinculado a un objeto, un proceso (edure) es un objeto en sí mismo y, por lo tanto, puede llamarse como una función. – akuhn

+0

@Adrian da método independiente. prueba tú mismo: 'ruby -e 'def f; "foo"; fin; obj = método: f; puts obj.call'' – mykhal

0

debe crear un objeto Proc si quieres un objeto función

f = Proc.new { |x| x * 2 } 

llamar a la función utilizando

f.call(8) # => 16 

o

f[8] # => 16 

incluso se puede utilizar esta función objeto en una operación map

[1, 2, 3, 4, 5].map(&f) # => [2, 4, 6, 8, 10] 
Cuestiones relacionadas