【问题标题】:Is it possible to have class.property = x return something other than x?是否有可能让 class.property = x 返回 x 以外的东西?
【发布时间】:2014-05-12 18:38:10
【问题描述】:

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

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

【问题讨论】:

    标签: ruby properties setter


    【解决方案1】:

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

    $ 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...我想我不会链接并行分配:)

    好问题!

    【讨论】:

    • 我首先将其读作“如果您定义了这样的访问器,您将破坏链式赋值语义”。正如 rampion 的回答所表明的那样,情况并非如此:分配方法的返回值通常被忽略。 Martin 的意思是“语言不允许你这样做;如果这样做,你会破坏链式赋值语义”。
    【解决方案2】:

    正如 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
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-12
        • 2010-10-15
        相关资源
        最近更新 更多