请考虑以下代码段:
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
显然并不总是等同于直接调用方法的行为。
答案 0 :(得分:19)
这就是作业的工作原理;返回值被忽略,赋值表达式的结果始终是右侧值。这是Ruby语法的基本特征。 left-hand side = right-hand side
始终评估为right-hand side
,无论左手边是变量(x
),方法(object.x)
,常量(X
)还是任何表达。
来源:Programming Languages | Ruby IPA Ruby Standardization WG Draft,11.4.2.2.5,单方法分配
考虑分配链接x = y = 3
。
要使其正常工作,y = 3
的结果必须为3
,无论y=
方法返回的实际值如何。 x = y = 3
打算将y = 3; x = 3
,而不是视为y = 3; x = y
,如果y=
的返回值被视为y = 3
的结果。
或者考虑可以使用所有其他地方的作业。有时候,而不是......
obj.x = getExpensiveThing()
if obj.x
...
......我们写这个......
if obj.x = getExpensiveThing()
如果obj.x = ...
的结果可能是任意的,无效,但我们知道它会起作用,因为{{1}的结果总是 obj.x = y
。
<强>更新强>
问题的comment表明:
有趣的是,我没有意识到这种情况。似乎method =返回给出的任何输入......
否,这是一个重要的区别。这与方法赋值的返回值无关,它肯定不“返回给定的任何输入”,它返回告诉它返回的任何内容。 / p>
重点是语言的语法忽略了返回值;赋值不会计算y
方法的返回值,但返回值仍然存在,如问题本身所示:attr=
。这是有效的,因为不是赋值。你是支持Ruby语言的那一部分。
再次更新
要明确:我的示例中的Example.new.send(:my_attr=, 5) # => 15
和x
不应被解释为文字Ruby变量,它们是任务的任何有效左侧的占位符。 y
或x
可以任何表达式:y
,a
,obj.a
,CONSTANT_A
,{{1 },它是所有相同的。 赋值的值始终是右侧。