ruby - 为什么 Ruby setter 返回传递的值,而不是实例变量的最终值?

标签 ruby semantics setter

通常,Ruby 方法返回方法中最后一个表达式的值。然而,对于name=形式的setter来说,看起来像

给出以下代码:

class Foo
  attr_reader :bar

  def set_bar(v)
    @bar = (v + 1)
  end

  def bar=(v)
    @bar = (v + 1)
  end
end

如果我调用 bar=set_bar()@bar 的值是相同的:

f = Foo.new; f.set_bar(1); f.bar
# => 2

f = Foo.new; f.bar=1; f.bar
# => 2

但是,setter 的返回值是不同的:

f = Foo.new; f.set_bar(1)
# => 2
f = Foo.new; f.bar = 1 
# => 1                    
# note: irb in Ruby 2.7+ suppresses this unless you write (f.bar = 1)

即使我添加显式返回,这种情况仍然存在:

class Foo
  def bar=(v)
    @bar = (v + 1)
    return @bar
  end
end

f = Foo.new; f.bar = 1 
# => 1

这令人惊讶(我知道,Matz 已经明确表示 Ruby 不遵循最小惊喜原则)并且没有明显记录在任何地方。有记录吗?有什么原因吗?

最佳答案

所有赋值总是计算到右侧。是否是一个并不重要

  • 局部变量赋值:

    foo = 42 #=> 42
    
  • 实例变量赋值

    @foo = 42 #=> 42
    
  • 类变量赋值

    @@foo = 42 #=> 42
    
  • 全局变量赋值

    $foo = 42 #=> 42
    
  • 常量赋值

    FOO = 42 #=> 42
    
  • 缩写赋值

    foo += 42 #=> 42
    foo -= 42 #=> 42
    foo *= 42 #=> 42
    foo /= 42 #=> 42
    foo %= 42 #=> 42
    foo <<= 42 #=> 42
    foo >>= 42 #=> 42
    foo |= 42 #=> 42
    foo &= 42 #=> 42
    foo ||= 42 #=> 42
    foo &&= 42 #=> 42
    
  • 方法赋值

    foo.bar = 42 #=> 42
    

请注意,返回值并未完全被忽略:

f.public_send(:bar=, 1)
#=> 2

Is it documented?

对于此类问题,我最喜欢的文档是 ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification 。您正在查找的部分是 11.4.2.2.5 单一方法分配

Is there a reason for it?

(matz 的)最少惊讶的一致性和原则:所有其他赋值在 Ruby 中都计算到右侧。事实上,在几乎所有赋值为表达式的语言中,赋值的计算结果都是右侧。

因此,方法分配也评估其右侧是有意义的。

关于ruby - 为什么 Ruby setter 返回传递的值,而不是实例变量的最终值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65226532/

相关文章:

php - 如何在mysql中基于语义进行搜索

nlp - 如何获取单词的语义类型?

python - 对 python 类同时使用 __setattr__ 和描述符

ruby-on-rails - Rails 3.1 - 数据导入时拆分列?

html - 设计称呼

JavaScript:覆盖 get 和 set 但保留 native 功能

java - setter 未更新变量

ruby-on-rails - RoR API - 当我将数据库从 sqlite 切换到 postgres 时,API 数组中的任何更新对象都被移动到数组末尾

ruby - 截断不匹配的部分字符串

ruby-on-rails - 如何将 "where not"子句与 searchkick 一起使用