class.property = x 是否可以返回除 x 之外的其他内容?

发布于 2024-07-16 01:56:51 字数 441 浏览 5 评论 0原文

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

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

Let's say I have a Ruby class:

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

If I try and do MyClass.property=x, the return value of the whole statement is always x. It is a convention in a lot of C-based/inspired languages to return a boolean "success" value - is it possible to do this for a setter using the "equals syntax" in Ruby?

Furthermore - if this isn't possible, why not? Is there any conceivable downside to allowing an "equals setter" operation return a value?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

傾城如夢未必闌珊 2024-07-23 01:56:52

正如马丁所说,这将打破分配链。

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

但是,Ruby 方法有例外情况 - 如果出现问题期间
分配,引发异常。 那么如果出现问题,所有调用者都必须处理它
错误,与返回值不同,它很容易被忽略:

# 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

Like Martin says, this would break assignment chaining.

The way ruby assignment methods are defined to work expands MyClass.property = 3 to the equivalent of (lambda { |v| MyClass.send('property=', v); v })[3] (not really, but this shows how chaining works). The return value of the assignment is always the value assigned.

If you want to see the result of your MyClass#property= method, then use #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

However, the ruby way to do this is with exceptions - if something goes wrong during
the assignment, raise an exception. Then all invokers must handle it if something goes
wrong, unlike a return value, which can be easily ignored:

# 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
无言温柔 2024-07-23 01:56:52

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

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

I'm not a Ruby expert but I'd say no for that case I'm afraid. A property setter is solely there to set the value of a private field, not to have any side effects like returning result codes.

If you want that functionality then forget the setter and write a new method called TrySetProperty or something which tries to set the property and returns a boolean.

黑白记忆 2024-07-23 01:56:51

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

$ 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

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

好问题!

One downside is that you would break the chained assignment semantics:

$ 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> 

Consider:

x = MyClass.property = 3

Then x would take true if this worked as you had expected (right-associativity). That could be a surprise for people using your interface and used to the typical semantics.

You also got me thinking about parallel assignment, eg:

x, y = 1, 2

Apparently the return value from that expression is implementation specific... I guess I won't be chaining parallel assignments :)

Nice question!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文