Ich habe eine Methode innerhalb einer Methode. Die innere Methode hängt von einer variablen Schleife ab, die ausgeführt wird. Ist das eine schlechte Idee?
Dies ist jedoch keine verschachtelte Methode. Ich wiederhole: Ruby hat keine verschachtelten Methoden.
Was dies ist, ist eine dynamische Methodendefinition. Wenn Sie laufen meth1, wird der Body von meth1ausgeführt. Der Body definiert zufällig eine Methode mit dem Namen meth2, weshalb Sie nach meth1einmaliger Ausführung aufrufen können meth2.
Aber wo ist meth2definiert? Nun, es ist offensichtlich nicht als verschachtelte Methode definiert, da es in Ruby keine verschachtelten Methoden gibt. Es ist definiert als eine Instanzmethode von Test1:
Test1.new.meth2
# Yay
Außerdem wird es natürlich jedes Mal neu definiert, wenn Sie Folgendes ausführen meth1:
Test1.new.meth1
# YayTest1.new.meth1
# test1.rb:3: warning: method redefined; discarding old meth2# test1.rb:3: warning: previous definition of meth2 was here# Yay
Kurz gesagt: Nein, Ruby unterstützt keine verschachtelten Methoden.
Beachten Sie auch, dass in Ruby Methodenkörper keine Abschlüsse sein können, sondern nur Blockkörper. Dadurch entfällt der Hauptanwendungsfall für verschachtelte Methoden, da selbst wenn Ruby verschachtelte Methoden unterstützt, Sie die Variablen der äußeren Methode nicht in der verschachtelten Methode verwenden können.
UPDATE FORTSETZUNG: Zu einem späteren Zeitpunkt könnte diese Syntax dann erneut zum Hinzufügen verschachtelter Methoden zu Ruby verwendet werden. Dies würde sich so verhalten, wie ich es beschrieben habe: Sie würden auf ihre enthaltende Methode beschränkt sein, dh außerhalb ihrer enthaltenden Methode unsichtbar und unzugänglich Körper. Und möglicherweise hätten sie Zugriff auf den lexikalischen Bereich ihrer enthaltenen Methode. Wenn Sie jedoch die Diskussion lesen, die ich oben verlinkt habe, können Sie feststellen, dass matz stark gegen verschachtelte Methoden ist (aber immer noch zum Entfernen verschachtelter Methodendefinitionen).
Sie können jedoch auch zeigen, wie Sie ein Abschluss-Lambda in einer Methode für DRYness erstellen oder eine Rekursion ausführen.
Phrogz
119
Ich habe das Gefühl, dass Ruby möglicherweise keine verschachtelten Methoden hat.
Mark Thomas
16
@ Mark Thomas: Habe ich vergessen zu erwähnen, dass Ruby keine verschachtelten Methoden hat? :-) Im Ernst: ich zu der Zeit diese Antwort schrieb, gab es bereits drei Antworten, beansprucht jeder einzelne von denen , dass Ruby tut verschachtelte Methoden. Einige dieser Antworten hatten sogar positive Stimmen, obwohl sie offensichtlich falsch waren. Einer wurde sogar wieder vom OP akzeptiert, obwohl er falsch lag. Das Code-Snippet, mit dem diese Antwort beweist, dass Ruby verschachtelte Methoden unterstützt, beweist tatsächlich das Gegenteil, aber anscheinend haben sich weder die Upvoter noch das OP tatsächlich die Mühe gemacht, dies zu überprüfen. Also gab ich für jede falsche eine richtige Antwort. :-)
Jörg W Mittag
10
Wenn Sie feststellen, dass dies alles nur Anweisungen an den Kernel sind, die Tabellen ändern, und dass Methoden, Klassen und Module nur Einträge in Tabellen sind und nicht wirklich real, werden Sie wie Neo, wenn er sieht, wie die Matrix aussieht. Dann könnte man wirklich philosophisch werden und sagen, dass es neben verschachtelten Methoden nicht einmal Methoden gibt. Es gibt nicht einmal Agenten. Sie sind Programme in der Matrix. Sogar das saftige Steak, das Sie essen, ist nur ein Eintrag in einem Tisch.
Mydoghaswürmer
3
Es gibt keine Methoden, Ihr Code ist nur eine Simulation in The Matrix
bbozo
12
Eigentlich ist es möglich. Sie können hierfür procs / lambda verwenden.
def test(value)
inner =->(){
value * value
}
inner.call()end
Sie liegen nicht falsch, aber Ihre Antwort ist eine Lösung, um verschachtelte Methoden zu erreichen. In Wirklichkeit verwenden Sie nur Procs, die keine Methoden sind. Es ist eine gute Antwort außerhalb der Behauptung, "verschachtelte Methoden" zu lösen
Brandon Buck
5
Nein, nein, Ruby hat verschachtelte Methoden. Überprüfen Sie dies:
inner_method ist keine Methode, sondern eine Funktion / lambda / proc. Es gibt keine zugeordnete Instanz einer Klasse, daher handelt es sich nicht um eine Methode.
Sami Samhuri
2
Sie können so etwas tun
moduleMethods
define_method :outer do
outer_var =1
define_method :inner do
puts "defining inner"
inner_var = outer_var +1end
outer_var
end
extend selfendMethods.outer
#=> defining inner#=> 1Methods.inner
#=> 2
Dies ist nützlich, wenn Sie beispielsweise DSLs schreiben, bei denen der Gültigkeitsbereich zwischen den Methoden geteilt werden muss. Ansonsten ist es viel besser, etwas anderes zu tun, da es, wie in den anderen Antworten angegeben, innerbei jedem outerAufruf neu definiert wird. Wenn Sie dieses Verhalten möchten und manchmal auch möchten, ist dies ein guter Weg, um es zu bekommen.
Der Ruby-Weg besteht darin, es mit verwirrenden Hacks zu fälschen, bei denen sich einige Benutzer fragen: "Wie zum Teufel funktioniert das überhaupt?", Während die weniger Neugierigen sich einfach die Syntax merken, die für die Verwendung des Dings erforderlich ist. Wenn Sie jemals Rake oder Rails verwendet haben, haben Sie so etwas gesehen.
Hier ist so ein Hack:
def mlet(name,func)
my_class =(Class.new dodef initialize(name,func)@name=name
@func=func
enddef 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"endendend)yield my_class.new(name,func)end
Damit wird eine Methode der obersten Ebene definiert, die eine Klasse erstellt und an einen Block übergibt. Die Klasse gibt method_missingvor, eine Methode mit dem von Ihnen gewählten Namen zu haben. Es "implementiert" die Methode, indem es das Lambda aufruft, das Sie bereitstellen müssen. Indem Sie das Objekt mit einem Namen aus einem Buchstaben benennen, können Sie den Umfang der zusätzlichen Eingabe minimieren, die erforderlich ist (was auch bei Rails der Fall ist schema.rb). mletist nach der Common Lisp-Form benannt flet, außer wo ffür "Funktion" msteht , steht für "Methode".
Es ist möglich, eine ähnliche Vorrichtung zu erstellen, mit der mehrere innere Funktionen ohne zusätzliche Verschachtelung definiert werden können, für die jedoch ein noch hässlicherer Hack erforderlich ist, wie Sie ihn möglicherweise in der Implementierung von Rake oder Rspec finden. Wenn Sie herausfinden, wie Rspecs let!Arbeiten Sie dazu bringen, einen so schrecklichen Gräuel zu erschaffen.
Antworten:
UPDATE: Da diese Antwort in letzter Zeit ein gewisses Interesse gefunden zu haben scheint, wollte ich darauf hinweisen, dass es eine Diskussion über den Ruby Issue Tracker gibt, um die hier diskutierte Funktion zu entfernen , nämlich zu verbieten , Methodendefinitionen in einem Methodenkörper zu haben .
Nein, Ruby hat keine verschachtelten Methoden.
Sie können so etwas tun:
Dies ist jedoch keine verschachtelte Methode. Ich wiederhole: Ruby hat keine verschachtelten Methoden.
Was dies ist, ist eine dynamische Methodendefinition. Wenn Sie laufen
meth1
, wird der Body vonmeth1
ausgeführt. Der Body definiert zufällig eine Methode mit dem Namenmeth2
, weshalb Sie nachmeth1
einmaliger Ausführung aufrufen könnenmeth2
.Aber wo ist
meth2
definiert? Nun, es ist offensichtlich nicht als verschachtelte Methode definiert, da es in Ruby keine verschachtelten Methoden gibt. Es ist definiert als eine Instanzmethode vonTest1
:Außerdem wird es natürlich jedes Mal neu definiert, wenn Sie Folgendes ausführen
meth1
:Kurz gesagt: Nein, Ruby unterstützt keine verschachtelten Methoden.
Beachten Sie auch, dass in Ruby Methodenkörper keine Abschlüsse sein können, sondern nur Blockkörper. Dadurch entfällt der Hauptanwendungsfall für verschachtelte Methoden, da selbst wenn Ruby verschachtelte Methoden unterstützt, Sie die Variablen der äußeren Methode nicht in der verschachtelten Methode verwenden können.
UPDATE FORTSETZUNG: Zu einem späteren Zeitpunkt könnte diese Syntax dann erneut zum Hinzufügen verschachtelter Methoden zu Ruby verwendet werden. Dies würde sich so verhalten, wie ich es beschrieben habe: Sie würden auf ihre enthaltende Methode beschränkt sein, dh außerhalb ihrer enthaltenden Methode unsichtbar und unzugänglich Körper. Und möglicherweise hätten sie Zugriff auf den lexikalischen Bereich ihrer enthaltenen Methode. Wenn Sie jedoch die Diskussion lesen, die ich oben verlinkt habe, können Sie feststellen, dass matz stark gegen verschachtelte Methoden ist (aber immer noch zum Entfernen verschachtelter Methodendefinitionen).
quelle
Eigentlich ist es möglich. Sie können hierfür procs / lambda verwenden.
quelle
Nein, nein, Ruby hat verschachtelte Methoden. Überprüfen Sie dies:
quelle
Sie können so etwas tun
Dies ist nützlich, wenn Sie beispielsweise DSLs schreiben, bei denen der Gültigkeitsbereich zwischen den Methoden geteilt werden muss. Ansonsten ist es viel besser, etwas anderes zu tun, da es, wie in den anderen Antworten angegeben,
inner
bei jedemouter
Aufruf neu definiert wird. Wenn Sie dieses Verhalten möchten und manchmal auch möchten, ist dies ein guter Weg, um es zu bekommen.quelle
Der Ruby-Weg besteht darin, es mit verwirrenden Hacks zu fälschen, bei denen sich einige Benutzer fragen: "Wie zum Teufel funktioniert das überhaupt?", Während die weniger Neugierigen sich einfach die Syntax merken, die für die Verwendung des Dings erforderlich ist. Wenn Sie jemals Rake oder Rails verwendet haben, haben Sie so etwas gesehen.
Hier ist so ein Hack:
Damit wird eine Methode der obersten Ebene definiert, die eine Klasse erstellt und an einen Block übergibt. Die Klasse gibt
method_missing
vor, eine Methode mit dem von Ihnen gewählten Namen zu haben. Es "implementiert" die Methode, indem es das Lambda aufruft, das Sie bereitstellen müssen. Indem Sie das Objekt mit einem Namen aus einem Buchstaben benennen, können Sie den Umfang der zusätzlichen Eingabe minimieren, die erforderlich ist (was auch bei Rails der Fall istschema.rb
).mlet
ist nach der Common Lisp-Form benanntflet
, außer wof
für "Funktion"m
steht , steht für "Methode".Sie verwenden es so:
Es ist möglich, eine ähnliche Vorrichtung zu erstellen, mit der mehrere innere Funktionen ohne zusätzliche Verschachtelung definiert werden können, für die jedoch ein noch hässlicherer Hack erforderlich ist, wie Sie ihn möglicherweise in der Implementierung von Rake oder Rspec finden. Wenn Sie herausfinden, wie Rspecs
let!
Arbeiten Sie dazu bringen, einen so schrecklichen Gräuel zu erschaffen.quelle
:-D
Ruby hat verschachtelte Methoden, nur dass sie nicht das tun, was Sie von ihnen erwarten würden
quelle