Tengo un método dentro de un método. El método interior depende de un bucle variable que se está ejecutando. ¿Es una mala idea?¿Es posible tener métodos dentro de los métodos?
Respuesta
ACTUALIZACIÓN: Dado que esta respuesta parece haber despertado cierto interés últimamente, quería señalar que existe discussion on the Ruby issue tracker to remove the feature discussed here, namely to forbid having method definitions inside a method body.
No, Ruby no tiene métodos anidados.
se puede hacer algo como esto:
class Test1
def meth1
def meth2
puts "Yay"
end
meth2
end
end
Test1.new.meth1
Pero eso es no un método anidado. Repito: Ruby no tiene métodos anidados.
Qué es esto, es una definición de método dinámico. Cuando ejecuta meth1
, se ejecutará el cuerpo de meth1
. El cuerpo simplemente define un método llamado meth2
, por lo que después de ejecutar meth1
una vez, puede llamar al meth2
.
¿Pero dónde se define meth2
? Bueno, obviamente es no definido como un método anidado, ya que no hay no son métodos anidados en Ruby. Se define como un método de instancia de Test1
:
Test1.new.meth2
# Yay
Además, es obvio que se volverá a definir cada vez que ejecute meth1
:
Test1.new.meth1
# Yay
Test1.new.meth1.
# test1.rb:3: warning: method redefined; discarding old meth2
# test1.rb:3: warning: previous definition of meth2 was here
# Yay
En resumen: no, Ruby no apoyo anidado métodos.
Tenga en cuenta también que en Ruby, los cuerpos de método no pueden ser cierres, solo los cuerpos de bloque pueden hacerlo. Esto prácticamente elimina el uso principal de los métodos anidados, ya que incluso si Ruby admitía métodos anidados, no podría usar las variables del método externo en el método anidado.
ACTUALIZACIÓN CONTINUACIÓN: en una etapa más tarde, a continuación, esta sintaxis puede ser reutilizado para la adición de métodos anidados a Ruby, que se comportan de la manera que he descrito: serían el ámbito a su método que contiene, es decir, invisible e inaccesible fuera de su cuerpo de método contenedor. Y posiblemente, tendrían acceso al alcance léxico de su método contenedor. Sin embargo, si lee la discusión que he vinculado anteriormente, puede observar que matz está muy en contra de los métodos anidados (pero aún así para eliminar las definiciones de métodos anidados).
También podría mostrar, sin embargo, cómo crear una lambda de cierre en un método para DRYness, o ejecutar recursión. – Phrogz
Tengo la sensación de que Ruby podría no tener métodos anidados. –
@ Mark Thomas: ¿Olvidé mencionar que Ruby no tiene métodos anidados? :-) En serio: en el momento en que escribí esta respuesta, ya había tres respuestas, cada una de las cuales afirmaba que Ruby * does * tenía métodos anidados. Algunas de esas respuestas incluso tenían votaciones ascendentes a pesar de estar flagrantemente equivocadas. Uno fue incluso aceptado por el OP, nuevamente, a pesar de estar equivocado. El fragmento de código que la respuesta usa para probar que Ruby admite métodos anidados, en realidad demuestra lo contrario, pero aparentemente ni los videntes ni el OP se molestaron en verificarlo. Entonces, di una respuesta correcta para cada error. :-) –
No, no, Ruby tiene métodos anidados.Mira esto:
def outer_method(arg)
outer_variable = "y"
inner_method = lambda {
puts arg
puts outer_variable
}
inner_method[]
end
outer_method "x" # prints "x", "y"
inner_method no es un método, es una función/lambda/proc. No hay ninguna instancia asociada de ninguna clase, por lo que no es un método. –
:-D
Rubí ha anidado métodos, sólo que no hacen lo que se espera de ellos a
1.9.3p484 :001 > def kme; 'kme'; def foo; 'foo'; end; end
=> nil
1.9.3p484 :003 > self.methods.include? :kme
=> true
1.9.3p484 :004 > self.methods.include? :foo
=> false
1.9.3p484 :005 > kme
=> nil
1.9.3p484 :006 > self.methods.include? :foo
=> true
1.9.3p484 :007 > foo
=> "foo"
Este no es un método anidado ... ver la respuesta de * Jörg W Mittag * para una comprensión clara. – Hardik
Usted puede hacer algo como esto
module Methods
define_method :outer do
outer_var = 1
define_method :inner do
puts "defining inner"
inner_var = outer_var +1
end
outer_var
end
extend self
end
Methods.outer
#=> defining inner
#=> 1
Methods.inner
#=> 2
Esto es útil cuando estás haciendo cosas como escribir DSL que requieren compartir el alcance entre los métodos. Pero de lo contrario, es mucho mejor que haga cualquier otra cosa, porque como dicen las otras respuestas, inner
se redefine cuando se invoca outer
. Si quieres este comportamiento, y a veces puedes, esta es una buena forma de obtenerlo.
En realidad es posible. Puede usar procs/lambda para esto.
def test(value)
inner = ->() {
value * value
}
inner.call()
end
La forma Ruby es que fingir con hacks confusas que tendrán algunos usuarios se pregunta "¿Cómo diablos hace esto incluso trabajar?", Mientras que los menos curioso será simplemente memorizar la sintaxis necesaria para usar la cosa. Si alguna vez has usado Rake o Rails, has visto este tipo de cosas.
Aquí es un truco como:
def mlet(name,func)
my_class = (Class.new do
def initialize(name,func)
@name=name
@func=func
end
def method_missing(methname, *args)
puts "method_missing called on #{methname}"
if methname == @name
puts "Calling function #{@func}"
@func.call(*args)
else
raise NoMethodError.new "Undefined method `#{methname}' in mlet"
end
end
end)
yield my_class.new(name,func)
end
Lo que hace es definir un método de nivel superior que crea una clase y se lo pasa a un bloque. La clase usa method_missing
para pretender que tiene un método con el nombre que eligió. "Implementa" el método llamando a la lambda que debe proporcionar. Al nombrar el objeto con un nombre de una letra, puede minimizar la cantidad de tipeo adicional que requiere (que es lo mismo que hace Rails en su schema.rb
). mlet
lleva el nombre del formulario de Lisp común flet
, excepto donde f
significa "función", m
significa "método".
que lo utilice como esto:
def outer
mlet :inner, ->(x) { x*2 } do |c|
c.inner 12
end
end
Es posible hacer un artilugio similar que permite múltiples funciones internas que definirse sin anidación adicional, pero que requiere un corte aún más feo del tipo que podría encontrar en la implementación de Rake o Rspec. Entender cómo funciona el let!
de Rspec te ayudaría a crear una abominación tan horrible.
- 1. ¿Es posible tener una interfaz que tenga métodos privados/protegidos?
- 2. ¿Es posible identificar métodos alias en Ruby?
- 3. ¿Es posible simular los métodos de registro de NLog?
- 4. ¿Requiere declaraciones dentro de los métodos?
- 5. ¿Es posible tener demasiados métodos en términos de tamaño de pila y posible desbordamiento?
- 6. ¿Es posible sobrecargar los métodos múltiples de Clojure en Arity?
- 7. ¿Es posible redefinir los métodos Java de Clojure?
- 8. no implementando todos los métodos de interfaz. ¿Es posible?
- 9. ¿Es posible encadenar métodos de diferentes características?
- 10. ¿Qué es mejor? Los métodos estáticos o métodos de instancia
- 11. ¿Por qué no se permite sobrecargar los métodos dentro de los métodos (por ejemplo, cierres sobrecargados)?
- 12. ¿Los métodos LINQ son métodos de extensión?
- 13. llaves dentro de los parámetros de Javascript para los métodos
- 14. ¿Deben los métodos de extensión tener un prefijo?
- 15. Python: ¿es mejor tener múltiples métodos o muchos parámetros opcionales?
- 16. registrar todos los métodos?
- 17. ¿Es posible definir una interfaz no genérica que puede tener métodos genéricos?
- 18. clases Anónimo interior dentro Métodos
- 19. puedo tener RSpec sin una clase para los métodos
- 20. Java: ¿es posible generar la stacktrace con firmas de métodos?
- 21. Comparación: métodos de interfaz vs métodos virtuales vs métodos abstractos
- 22. Rieles usando ayudantes incluidos dentro de los métodos de clase
- 23. Usando captadores dentro de los métodos de clase
- 24. ASP.NET ¿Es posible llamar a métodos dentro de Server Tag usando Eval()?
- 25. ¿Es posible crear métodos de extensión con Framework 2.0?
- 26. ¿Es posible utilizar OutputCache en mvc JsonResult métodos de controlador?
- 27. Métodos dentro del espacio de nombres C#
- 28. Métodos de instancia llamando a métodos de clase llamando a los métodos de instancia
- 29. Inspeccionar los métodos S4
- 30. ambigüedad entre los métodos
Puede compartir el ejemplo del código o al menos un equivalente lógico de lo que está tratando de hacer. –