假设我有一个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中的“equals语法”为setter执行此操作?
此外 - 如果不可能,为什么不呢?允许“等于设定者”操作返回值是否有任何可以想象的缺点?
答案 0 :(得分:11)
一个缺点是你会打破链式赋值语义:
$ 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
显然,该表达式的返回值为implementation specific ...我想我不会链接并行赋值:)
好问题!
答案 1 :(得分:7)
就像马丁所说,这会打破分配链。
将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
答案 2 :(得分:5)
我不是红宝石专家,但我不敢对那个案例说不。属性设置器只用于设置私有字段的值,不会产生任何副作用,如返回结果代码。
如果你想要那个功能,那么就忘记了setter并写了一个名为TrySetProperty
的新方法,或者尝试设置属性并返回布尔值的东西。