为什么`method =`不像其他方法一样处理?

doo*_*ree 11 ruby

请考虑以下代码段:

class Example
  def my_attr=(value)
    @_my_attr = value
    @_my_attr * 3
  end
end
Run Code Online (Sandbox Code Playgroud)

我希望表达式Example.new.my_attr = 5返回15,但结果证明是错误的.即使我=明确调用该方法,也始终返回原始返回值:

Example.new.my_attr = 5 # => 5
Example.new.my_attr=(5) # => 5
Run Code Online (Sandbox Code Playgroud)

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

更新:感谢@jeffgran:

Example.new.send(:my_attr=, 5) # => 15
Run Code Online (Sandbox Code Playgroud)

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

mea*_*gar 21

这就是作业的工作原理; 返回值被忽略,赋值表达式的结果始终是右侧值.这是Ruby语法的基本特征.无论左手边是变量(),方法,常量()还是任何表达式,left-hand side = right-hand side总是会评估为.right-hand sidex(object.x)X

来源:编程语言| Ruby IPA Ruby Standardization WG Draft,11.4.2.2.5,Single method assignment


考虑分配链接,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 
  ...
Run Code Online (Sandbox Code Playgroud)

......我们写这个......

if obj.x = getExpensiveThing()
Run Code Online (Sandbox Code Playgroud)

不能工作,如果结果obj.x = ...可以是任意的事情,但我们知道它会奏效,因为结果obj.x = y永远 y.

更新

对该问题的评论指出:

有趣的是,我没有意识到这种情况.似乎method =返回给出的任何输入...

,这是一个重要的区别.这与方法赋值的返回值无关,它肯定不会 "返回给出的任何输入",它返回你告诉它返回的任何内容.

重点是语言的语法忽略了返回值; 赋值不会计算attr=方法的返回值,但返回值仍然存在,如问题本身所示:Example.new.send(:my_attr=, 5) # => 15.这是有效的,因为它不是任务.你是支持Ruby语言的那一部分.

再次更新

要明确:x并且y在我的示例中不应该被解释为文字Ruby变量,它们是任务的任何有效左侧的占位符.x或者y可以是任意表达式:a,obj.a,CONSTANT_A,Something::a,@instance_a,这都是一样的.任务的价值始终是右手边.

  • 赋值和setter方法不同.如果你做'y = 3`(事先没有任何方法定义),那么就没有你所写的"y =`方法".这是一项任务.OP的观点是关于setter方法,而不是赋值.作业无关紧要.它们在语法上有明显的区别.setter方法总是需要一个明确的接收器.分配从未出现在接收器上.但是,有可能设置setter方法的行为类似于赋值,因为它们在表面看起来相似. (2认同)