12

假设我有一个 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 中使用“等于语法”为 setter 执行此操作?

此外 - 如果这是不可能的,为什么不呢?允许“等于设置器”操作返回值是否有任何可能的缺点?

4

3 回答 3

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

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

好问题!

于 2009-04-02T08:14:22.383 回答
7

正如 Martin 所说,这会破坏分配链。

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
于 2009-04-02T12:12:07.273 回答
5

我不是 Ruby 专家,但恐怕我会拒绝这种情况。属性设置器仅用于设置私有字段的值,不会产生任何副作用,例如返回结果代码。

如果您想要该功能,请忘记设置器并编写一个名为的新方法TrySetProperty或尝试设置属性并返回布尔值的东西。

于 2009-04-02T07:19:08.757 回答