setter方法返回self不工作,这是一个bug?

时间:2014-05-12 10:16:51

标签: ruby

我想迭代一个字符串数组,并将它们分配给一个新的User类实例,我希望我会得到一个User对象数组:

class User
  def name=(name)
    @name = name
    self
  end
end

original_array = ["aaa", "bbb", "bbb"]
result = original_array.collect { |str| User.new.name = str }

但结果是一个字符串数组!

puts result.inspect            # => ["aaa", "bbb", "bbb"]
puts result === original_array # => true

我不知道我哪里出错了?

1 个答案:

答案 0 :(得分:5)

这里错误的是User.new.name = str会返回str,因此会收集str的值。

为什么会返回str?因为,与任何其他Ruby方法相反,每个Ruby setter方法都返回传递的值,而不管方法中的返回值。有关此行为的更多信息,您可以查看this other SO answer

在IRB-ready概念证明之下:

def name=(name)
  @name = 'another value'
end

returned_value = (self.name = 'a value')

returned_value #=> 'a value'
@name          #=> 'another value'

您可以通过以下方式完成所需的工作:

  • 此语法对任何Ruby对象都有效,因为它使用Object#tap

    User.new.tap { |v| v.name = str }
    
  • 如果UserActiveRecord模型,我猜你可以使用其中一种略短的语法:

    User.new name: str
    User.new { |v| v.name = str }