是否有可能让class.property = x返回x以外的东西?

假设我有一个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执行此操作?

此外 – 如果不可能,为什么不呢? 允许“等于设定者”操作返回值是否有任何可以想象的缺点?

一个缺点是你会打破链式赋值语义:

 $ irb irb(main):001:0> x = y = 3 => 3 irb(main):002:0> px 3 => nil irb(main):003:0> py 3 => nil irb(main):004:0> 

考虑:

 x = MyClass.property = 3 

如果按预期工作(右关联性),则xtrue 。 对于使用您的界面并习惯于典型语义的人来说,这可能是一个惊喜。

你还让我考虑并行分配,例如:

 x, y = 1, 2 

显然,该表达式的返回值是特定于实现的 …我想我不会链接并行赋值:)

好问题!

就像马丁说的那样,这会打破分配链。

ruby赋值方法被定义为工作的方式将MyClass.property = 3扩展为等效于(lambda { |v| MyClass.send('property=', v); v })[3] (不是真的,但是这表明如何链接工作)。 赋值的返回值始终是赋值。

如果要查看MyClass#property= method的结果,请使用#send

 irb> o = Object.new => # irb> def ox=(y) irb> @x = y+1 irb> puts "y = #{y}, @x = #@x" irb> true irb> end => nil irb> def ox irb> puts "@x = #@x" irb> @x irb> end => nil irb> ox = 4 y = 4, @x = 5 => 4 irb> ox @x = 5 => 5 irb> o.send('x=', 3) y = 3, @x = 4 => true 

但是,执行此操作的ruby方式有例外 – 如果在分配期间出现问题,则引发exception。 然后,如果出现问题,所有调用者都必须处理它,而不像返回值,这很容易被忽略:

 # continued from above... irb> def ox=(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> ox = 4 y = 4, @x = 5 => 4 irb> ox = 0 ArgumentError: new value must be > 0 from (irb):12 from :0 irb> ox = "3" ArgumentError: new value must be > 0 from (irb):13 from :0 irb> ox @x = 5 => 5 

我不是Ruby专家,但是我不敢说那个案子我不敢。 属性设置器仅用于设置私有字段的值,而不具有返回结果代码等任何副作用。

如果你想要那个function,那么就忘记了setter并编写了一个名为TrySetProperty的新方法,或尝试设置属性并返回布尔值的方法。