Archiv verlassen und diese Seite im Standarddesign anzeigen : Gibt es lokale "Script" Variablen?
Meine heutige Frage:
Kann ich innerhalb einer Klasse eine lokale Variable auf eine Methode verweisen lassen?
Als Beispiel etwas in der Art:
class Example_Class
attr_accessor :method
def initialize(method)
@method = method
self.@method
end
def example_method
self.do_stuff
end
end
wobei die Variable @method dann 'example_method' speichern würde und ich damit dann exakt diese Methode aufrufen könnte.
Ich weis, dass diese Methode nicht funktioniert, worum es mir hiermit vielmehr geht ist ob eine Vorgehensweise nach diesem Schema in irgendeinerweise möglich wäre.
Falls es dies nicht ist, würde es mich auch sehr freuen falls ihr mir dies mitteilen könntet anstatt diese Frage unbeantwortet zu lassen da ihr euch nicht hundert prozentig sicher seid.
Ich danke schoneinmal für jede Antwort.
Cornix.
The_Burrito
22.01.2010, 15:07
Das geht in der Tat. Dafür brauchst du nur ein Objekt der Klasse Method oder UnboundMethod
Solche Objekt erhältst du indem du die Methode method eines beliebigen Objektes aufrufst oder instance_method für Klassen und Module.
Mit der Methode call eines solchen Objektes kannst du die entsprechende Methode dann aufrufen.
Beispiel:
m = 12.method(:to_s)
m.call # => "12"
m = 12.method("+")
m.call(12) # => 24
m = "abc".method(:reverse)
m.call # => "cba"
Ein Method Objekt merkt sich dabei immer den Empfänger von dem es ermittelt wurde.
Hast du eine Instanz von UnboundMethod musst du dieses erst mit der bind Methode einer Instanz von einem Objekt zuweisen.
Tut mir leid aber ich scheine wohl beim Versuch das zu verstehen an meine Grenzen zu stoßen.
Also, du sagst ich brauche eine neue Klasse "Methode" ist das korrekt?
Und diese ist nicht vorgefertigt oder ist sie es doch?
und über folgenden Befehl:
m = example_method.method(:to_s)
könnte ich die Methode 'example_method' in der lokalen Variable m speichern und über m.call abrufen?
Wobei 'm' dann eine Instanz dieser neuen Methoden Klasse wäre?
Falls dies falsch ist bitte ich um Verbesserung, es ist mir noch einiges unklar. Vielen Dank aber schoneinmal für diesen Beitrag.
Cornix
The_Burrito
23.01.2010, 22:28
Nein. Die Klasse heißt Method und nicht Methode (also Englisch, und nicht Deutsch).
Eine Instanz von dieser Klasse bekommst du wenn du von einem beliebigen Objekt, die methode method aufrufst. Als Parameter erwartet diese Methode den Namen der Methode die du haben möchtest.
Hast du jetzt z.B. eine Instanz vom Typ Numeric kannst du dir von dieser Instanz aus quasi eine Referenz auf jede ihrer Methoden holen.
Beispiel:
i = 12 # Weist der Variable i eine Instanz vom Typ Numeric zu
m = i.method(:to_s) # m ist jetzt eine Instanz vom Typ Method welche auf die Methode to_s von i verweist
m.call # Ruft die Methode to_s auf, welche an i gebunden ist
i.to_s # Gleichwertig mit dem oberen Statement
Okay, nun verstehe ich soweit, vielen Dank.
Allerdings muss ich sagen, dass mein erster Versuch damit kläglich gescheitert ist.
Hier ein simpler Test-Code:
class Example_Class
attr_accessor :method
def initialize
@m = Example_Class.method(example_method)
@m.call
end
def example_method
print("hi")
end
end
Die Nachricht "hi" wird korrekt angezeigt wenn ich diesen Script starte, allerdings folgt direkt darauf folgende Fehlermeldung:
Script '' line 6: TypeError occured.
nil is not a symbol
Welche ich nicht recht zu verstehen in der Lage bin. Besonders nicht in dem Zusammenhang mit meinem Script.
Vielen Dank für die Hilfe soweit.
Cornix.
The_Burrito
24.01.2010, 22:03
Die method Methode erwartet entweder ein Symbol oder einen String mit dem namen der Methode die du haben willst.
Also entweder :hehe:xample_method (der : ist erforderlich) oder "example_method".
Außerdem kriegst du beim Aufruf der method Methode für eine Klasse keine Instanz von Method sondern von UnboundMethod. Diese musst du erst an einen Empfänger binden bevor du sie verwenden kannst.
Beispiel:
c = Example_Class.new
m = Example_Class.method(:example_method)
m.bind(c)
m.call # Gleichwertig mit c.example_method
Tut mir leid, ich scheine wohl einfach kein glückliches Händchen dafür zu haben. Meine Klasse sieht nun wie folgt aus:
class Test
def initialize
@m = Test.method(:example_method)
@m.bind(self)
@m.call
end
def example_method
print("hi")
end
end
Soweit nichts sonderlich kompliziertes (ich hoffe ich darf die Methode @m an die eigene Klasse binden) allerdings erhalte ich nun bei jedem Versuch folgenden Fehler:
Script '' line 4: NameError occured
undefinde Method 'example_method' for class 'Class'
Diese Fehlernachricht ergibt soweit Sinn, allerdings nicht im Kontext.
Einmal wieder bitte ich um Aufklärung, vielen Dank für die ganze Mühe und Zeit.
The_Burrito
25.01.2010, 06:43
Wenn du schon im vorhinein den Empfänger kennst (in deinem Fall also self) wäre es sinnvoller, die Methode direkt vom Emfänger abzufragen, also self.method(:example_method). Dann kannst du dir den bind aufruf sparen.
Der Code wie du ihn geschrieben hast, funktioniert wenn du Example_Class.instance_method aufrufst. Hab ich in meinem letzten Post übersehen.
Das führt zu zwei möglichkeiten:
class Test
def initialize
@m = Test.instance_method(:example_method)
@m = @m.bind(self) # bind liefert nur eine Method instanz die an self gebunden ist zurück, bindet es aber nicht an @m
@m.call
end
def example_method
print("hi")
end
end
class Test
def initialize
@m = self.method(:example_method) # Liefert ein Method Objekt, welches direkt an self gebunden ist
@m.call
end
def example_method
print("hi")
end
end
Jetzt funktioniert es, vielen vielen Dank.
Dies hier war was ich übersehen habe:
@m = @m.bind(self)
habe ich mit
@m.bind(self)
verwechselt.
Es brauchte eine lange Zeit aber nun funktioniert es, vielen Dank.
Method-Objekte zu nutzen hat allerdings auch 'ne Menge Nachteile. Zum einen bekommst du wirklich nur Zugriff auf Methoden, nicht aber auf andere mögliche Responses von Objekten, weiterhin ist die Performance auch nicht so gut, weil die komplette Methode dabei im Speicher kopiert wird.
Der gängige Weg in Ruby um eine Methode mit einem variablen Namen und variablen Parametern auszuführen ist Object#send. Das bekommt als ersten Parameter den Namen der Methode (entweder als String oder Symbol) und zusätzlich noch die Parameter die man der Methode mitschicken will.
5.send(:+, 3) #=> 8
4.send("*", 8) #=> 32
a = [1, nil, 3, nil]
a.send("compact!") #=> [1, 3]
a.send(:push, 4, 5, 6) #=> [1, 3, 4, 5, 6]
Das ist natürlich eine sehr sehr nützliche Information, vielen Dank.
Powered by vBulletin® Version 4.2.3 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.