首页 > 解决方案 > 为什么 Ruby setter 返回传递的值,而不是实例变量的最终值?

问题描述

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

给定以下代码:

class Foo
  attr_reader :bar

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

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

如果我调用bar=or 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)

即使我添加了一个明确的,这仍然存在return

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

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

这很令人惊讶(我知道,Matz 明确表示 Ruby 不遵循最小意外原则),并且在任何地方都没有明显的记录。是否记录在案?有什么原因吗?

标签: rubysemanticssetter

解决方案


所有的分配总是在右手边求值。不管是不是一个

  • 局部变量赋值:

    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

是否记录在案?

对于此类问题,我最喜欢的文档是ISO/IEC 30170:2012信息技术 — 编程语言 — Ruby规范。您正在寻找的部分是 11.4.2.2.5 Single method assignments

有什么原因吗?

(matz's) Least Astonishment 的一致性和原则:在 Ruby 中,所有其他作业都在右侧计算。事实上,在几乎所有赋值是表达式的语言中,赋值都在右侧计算。

因此,方法分配也对它们的右侧进行评估是有意义的。


推荐阅读