Возможно ли, чтобы class.property = x возвращал что-то кроме x?
-
22-08-2019 - |
Вопрос
Допустим, у меня есть класс 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
Если я попытаюсь сделать MyClass.property=x
, возвращаемое значение всего оператора всегда равно x.Во многих языках, основанных на C/вдохновленных языком, принято возвращать логическое значение «успех». Можно ли сделать это для установщика, используя «синтаксис равенства» в Ruby?
Более того, если это невозможно, то почему бы и нет?Есть ли какой-либо мыслимый недостаток в том, чтобы разрешить операции установки равенства возвращать значение?
Решение
Недостатком является то, что вы нарушите семантику цепного присваивания:
$ 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>
Учитывать:
x = MyClass.property = 3
Затем x
взял бы true
если бы это сработало так, как вы ожидали (правая ассоциативность).Это может быть сюрпризом для людей, использующих ваш интерфейс и привыкших к типичной семантике.
Вы также заставили меня задуматься о параллельном присваивании, например:
x, y = 1, 2
Очевидно, возвращаемое значение из этого выражения равно конкретная реализация...Думаю, я не буду связывать параллельные задания :)
Хороший вопрос!
Другие советы
Как говорит Мартин, это нарушит цепочку заданий.
Способ определения методов назначения Ruby расширяется. MyClass.property = 3
эквиваленту (lambda { |v| MyClass.send('property=', v); v })[3]
(не совсем, но это показывает, как работает цепочка).Возвращаемое значение присваивания всегда является назначенным значением.
Если вы хотите увидеть результат своего MyClass#property=
метод, затем используйте #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
Однако рубиновый способ сделать это с исключениями - если что-то пойдет не так во время назначение, поднять исключение.Тогда все вызывающие должны справиться с этим, если что-то пойдет не так. неправильно, в отличие от возвращаемого значения, которое можно легко проигнорировать:
# 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
Я не эксперт по Ruby, но, боюсь, в этом случае я бы сказал нет.Средство установки свойств предназначено исключительно для установки значения частного поля, а не для каких-либо побочных эффектов, таких как возврат кодов результатов.
Если вам нужна эта функциональность, забудьте об установщике и напишите новый метод с именем TrySetProperty
или что-то, что пытается установить свойство и возвращает логическое значение.