E ' possibile avere classe.property = x tornare a qualcosa di diverso x?
-
22-08-2019 - |
Domanda
Diciamo che ho una classe Ruby:
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
Se provo a fare MyClass.property=x
, il valore di ritorno di tutta l'istruzione è sempre x.Si tratta di una convenzione in un sacco di C/ispirazione lingue per restituire un booleano "successo" valore - è possibile fare questo per un setter utilizzando la "sintassi è uguale a" Ruby?
Inoltre - se questo non è possibile, perché no?C'è qualche lato negativo concepibile consentendo un "uguale setter" operazione restituisce un valore?
Soluzione
Uno svantaggio è che si potrebbe rompere il incatenato assegnazione semantica:
$ 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>
Prendere in considerazione:
x = MyClass.property = 3
Quindi x
vorresti prendere true
se questo ha funzionato come previsto (destra-associatività).Che potrebbe essere una sorpresa per le persone che utilizzano l'interfaccia e utilizzato per la tipica semantica.
È inoltre mi ha fatto pensare parallelo di assegnazione, ad esempio:
x, y = 1, 2
A quanto pare il valore restituito dall'espressione che è implementazione di specifiche...Credo di non essere il concatenamento parallelo assegnazioni :)
Bella domanda!
Altri suggerimenti
Come afferma Martin, questo potrebbe rompere l'assegnazione di concatenamento.
Il modo in cui ruby i metodi di assegnazione sono definiti per il lavoro si espande MyClass.property = 3
per l'equivalente di (lambda { |v| MyClass.send('property=', v); v })[3]
(non proprio, ma questo dimostra come il concatenamento di opere).Il valore di ritorno della cessione è sempre il valore assegnato.
Se volete vedere il risultato del tuo MyClass#property=
il metodo, quindi utilizzare #send
:
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
Tuttavia, il rubino modo per farlo è con eccezioni - se qualcosa va storto durante l'assegnazione, sollevare un'eccezione.Quindi tutte armatura deve gestire, se qualcosa non va sbagliato, a differenza di un valore di ritorno, che può essere facilmente ignorato:
# 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
Io non sono un Rubino sono un esperto, ma direi di no per quel caso ho paura.Un setter è solo lì per impostare il valore di un campo privato, non ha effetti collaterali come tornare i codici di risultato.
Se si desidera che la funzionalità di dimenticare il setter e scrivere un nuovo metodo chiamato TrySetProperty
o qualcosa che tenta di impostare la proprietà e restituisce un valore booleano.