Ruby 递归函数的tap行为
我喜欢偶尔使用tap作为方法返回的美化工具。但是,当将tap与递归函数一起使用时,其行为与我预期的不同:Ruby 递归函数的tap行为,ruby,recursion,combinators,Ruby,Recursion,Combinators,我喜欢偶尔使用tap作为方法返回的美化工具。但是,当将tap与递归函数一起使用时,其行为与我预期的不同: class Node attr_accessor :name, :children def initialize(name); self.name, self.children = name, []; end def render res = "Name: #{name}\n" children.each do |child| res += " -
class Node
attr_accessor :name, :children
def initialize(name); self.name, self.children = name, []; end
def render
res = "Name: #{name}\n"
children.each do |child|
res += " - " + child.render + "\n"
end
res
end
end
parent = Node.new('Parent')
parent.children = [Node.new('Child')]
puts parent.render
返回
Name: Parent
- Name: Child
如果我将“渲染”功能更改为使用“点击”:
def render
"Name: #{name}\n".tap do |res|
children.each do |child|
res += " - " + child.render + "\n"
end
end
end
它回来了
Name: Parent
我假设该行为与第一个渲染函数相同。文档指出它“向块生成x,然后返回x”……因为函数正在递归,它是否污染了函数堆栈?这与任何事情都无关,只是赋值改变了变量,变量按值传递
tap
是不相关的,如果将字符串放入任何变量中,行为是相同的
在您的例子中,您将一个字符串文本传递到proc中,proc接收一个名为res
的变量,该变量包含该字符串的副本。然后修改该变量,而不是原始字符串本身
考虑:
def test(res)
res += "bar"
end
x = "foo"
test(x)
puts x # outputs "foo", not "foobar"
第一个示例之所以有效,是因为您正在用新值替换字符串
res
中的值。实际上,您并没有将数据附加到存储在res
string
中的字符串中,Ruby中的字符串是非常可变的。String
上有很多变异方法:字符串不是不可变的,但是无论何时使用赋值运算符,实际上都是在更改=
左侧引用的对象,而不是更改该对象的值。