Ist es möglich, class.property = x Rückkehr etwas anderes als x zu haben?
-
22-08-2019 - |
Frage
Lassen Sie uns sagen, dass ich eine Ruby-Klasse haben:
class MyClass
def self.property
return "someVal"
end
def self.property=(newVal)
# do something to set "property"
success = true
return success # success is a boolean
end
end
Wenn ich versuche, und tun MyClass.property=x
, der Rückgabewert der gesamten Aussage ist immer x. Es ist eine Konvention, in einer Menge von C-basierten / inspirierte Sprachen eines boolean „Erfolg“ Wert zurück - ist es möglich, dies für einen Setter zu tun mit der „gleich Syntax“ in Ruby
Außerdem - wenn dies nicht möglich ist, warum nicht? Gibt es einen denkbaren Nachteil so dass eine „gleich Setter“ Operation einen Wert zurückgeben?
Lösung
Ein Nachteil ist, dass Sie die verkettete Zuweisung Semantik brechen würde:
$ irb
irb(main):001:0> x = y = 3
=> 3
irb(main):002:0> p x
3
=> nil
irb(main):003:0> p y
3
=> nil
irb(main):004:0>
Bedenken Sie:
x = MyClass.property = 3
Dann würde x
true
wenn dies wie erwartet gearbeitet hatte (rechte Assoziativität). Das könnte eine Überraschung für Leute mit Ihrer Schnittstelle und die typischen Semantik verwendet.
Du hast auch denken, mich um parallele Zuordnung, zum Beispiel:
x, y = 1, 2
Anscheinend ist der Rückgabewert von diesem Ausdruck Implementierung spezifische ... Ich glaube, ich nicht parallel Zuweisungen werden Verkettungs:)
Nizza Frage!
Andere Tipps
Wie Martin sagt, dies würde Zuordnung Verkettungs brechen.
Die Art und Weise Rubin Zuordnungsverfahren zu arbeiten, sind definiert erweitert MyClass.property = 3
auf das Äquivalent von (lambda { |v| MyClass.send('property=', v); v })[3]
(nicht wirklich, aber dies zeigt, wie Verkettungs Werke). Der Rückgabewert des Auftrags ist immer der Wert zugewiesen.
Wenn Sie das Ergebnis Ihrer MyClass#property=
Methode sehen möchten, dann #send
verwenden:
irb> o = Object.new
=> #<Object:0x15270>
irb> def o.x=(y)
irb> @x = y+1
irb> puts "y = #{y}, @x = #@x"
irb> true
irb> end
=> nil
irb> def o.x
irb> puts "@x = #@x"
irb> @x
irb> end
=> nil
irb> o.x = 4
y = 4, @x = 5
=> 4
irb> o.x
@x = 5
=> 5
irb> o.send('x=', 3)
y = 3, @x = 4
=> true
Allerdings ist der rubin Weg, dies zu tun ist, mit Ausnahmen - wenn etwas schief geht während Die Zuordnung, eine Ausnahme ausgelöst. Dann werden alle Aufrufer muss damit umgehen, wenn etwas geht falsch, im Gegensatz zu einem Rückgabewert, die leicht ignoriert werden können:
# continued from above...
irb> def o.x=(y)
irb> unless y.respond_to? :> and (y > 0 rescue false)
irb> raise ArgumentError, 'new value must be > 0', caller
irb> end
irb> @x = y + 1
irb> puts "y = #{y}, @x = #@x"
irb> end
=> nil
irb> o.x = 4
y = 4, @x = 5
=> 4
irb> o.x = 0
ArgumentError: new value must be > 0
from (irb):12
from :0
irb> o.x = "3"
ArgumentError: new value must be > 0
from (irb):13
from :0
irb> o.x
@x = 5
=> 5
Ich bin kein Experte Rubin, aber ich würde sagen, nicht für den Fall, dass ich Angst habe. Eine Eigenschaft Setter ist es nur den Wert eines privaten Bereichs zu setzen, keine Nebenwirkungen zu haben, wie Ergebniscodes zurück.
Wenn Sie möchten, dass die Funktionalität dann die Setter vergessen und eine neue Methode namens TrySetProperty
oder etwas zu schreiben, die die Eigenschaft zu setzen versucht und gibt einen boolean.