为什么没有#String.tap返回修改后的字符串?

时间:2017-03-03 18:39:24

标签: ruby

我正在做

String.new.tap do |string|
  polygon.points.each do |point|
    x, y = point.x + (page_padding/2), point.y + (page_padding/2)
    string += "#{x}, #{y} "
  end
end

但它返回一个空字符串。

如果我打电话

Array.new.tap do |array|
  polygon.points.each do |point|
    x, y = point.x + (page_padding/2), point.y + (page_padding/2)
    array << "#{x}, #{y} "
  end
end

它返回一个修改过的数组。为什么这不适用于字符串?

使用Ruby 2.4.0

2 个答案:

答案 0 :(得分:5)

+=不是mutator:str1 += str2创建一个新字符串。使用<<来改变字符串:

string1 = 'foo'
string1.object_id
=> 70298699576220
(string1 += '2').object_id # changed
=> 70298695972240
(string1 << '2').object_id # not changed: original object has been mutated
=> 70298695972240

tap只是将自己产生于块,然后返回self。由于self在您的实例中没有变化,因此点击只返回原始值。

答案 1 :(得分:3)

解决方案

字符串

要从积分中获取字符串,只需使用mapjoin

polygon.points.map do |point|
  [point.x + (page_padding/2), point.y + (page_padding/2)].join(', ')
end.join(' ')

阵列

要获得一个aray,只需使用map

polygon.points.map do |point|
  [point.x + (page_padding/2), point.y + (page_padding/2)]
end

+和&lt;&lt;

+<<都可以在Array和Strings上使用,两个类的行为非常相似。 +创建一个新的数组或字符串,<<会改变原始数组或字符串。

s = "1 2"
#=> "1 2"
s + " 3"
#=> "1 2 3"
s
#=> "1 2"
s << " 3"
#=> "1 2 3"
s
#=> "1 2 3"
a = [1, 2]
#=> [1, 2]
a + [3]
#=> [1, 2, 3]
a
#=> [1, 2]
a << 3
#=> [1, 2, 3]
a
#=> [1, 2, 3]