11

考虑以下代码片段:

class Example
  def my_attr=(value)
    @_my_attr = value
    @_my_attr * 3
  end
end

我希望表达式Example.new.my_attr = 5返回15,但事实证明这是错误的。始终返回原始返回值,即使我=显式调用该方法:

Example.new.my_attr = 5 # => 5
Example.new.my_attr=(5) # => 5

Ruby 如何以及为什么这样做?Ruby 是否会处理以特殊结尾的方法=,还是其他机制?我想这排除了方法返回值的链接=,对吧?有没有办法让 Ruby 表现得不同,或者就是这样?

更新:感谢@jeffgran:

Example.new.send(:my_attr=, 5) # => 15

这是一种解决方法,但在另一个层面上更令人困惑,因为这send显然意味着在行为上并不总是等同于直接调用方法。

4

1 回答 1

21

这就是分配的工作方式;返回值被忽略,赋值表达式的结果总是右手边的值。这是 Ruby 语法的一个基本特征。无论左侧是变量 ( )、方法、常量 ( ) 还是任何表达式,都left-hand side = right-hand side将始终计算为。right-hand sidex(object.x)X

资料来源:编程语言 | Ruby IPA Ruby 标准化工作组草案,11.4.2.2.5,单一方法分配


考虑链接分配,x = y = 3.

为了使其正常工作,无论方法返回的实际值如何,结果都y = 3 必须是。应该读为,而不是如果将 from 的返回值视为 的结果,则暗示的内容。3y=x = y = 3y = 3; x = 3y = 3; x = yy=y = 3

或者考虑所有其他可以使用分配的地方。有时,而不是这个...

obj.x = getExpensiveThing()
if obj.x 
  ...

...我们写这个...

if obj.x = getExpensiveThing()

如果 的结果可以是任意的东西,这是行不通的,但我们知道起作用,因为 的结果总是。obj.x = ...obj.x = y y

更新

对该问题的评论指出:

有趣的是,我不知道这种情况。似乎 method= 返回给出的任何输入......

,这是一个重要的区别。这与方法分配的返回值无关,它绝对不会“返回任何输入”,它会返回你告诉它返回的任何内容。

关键是返回值被语言的语法忽略了;赋值不会计算attr=方法的返回值,但返回值仍然存在,正如问题本身所证明的那样:Example.new.send(:my_attr=, 5) # => 15。这是有效的,因为它不是 assignment。您正在回避 Ruby 语言的那一部分。

再次更新

明确一点:在我的示例中x,不应将其解释为文字 Ruby 变量,它们是assignment 任何有效左侧的y占位符。或者可以是任何表达式:, , , , ,都是一样的赋值的值总是在右边。xyaobj.aCONSTANT_ASomething::a@instance_a

于 2013-09-26T16:54:12.447 回答