2015-01-27 4 views
0

Мне нравится использовать краны иногда как средство для возврата метода. Однако, при использовании крана с рекурсивной функцией, это поведение отличается от того, что я ожидал:Поведение крана для рекурсивных функций

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» ... поскольку функция рекурсивно - это каким-то образом загрязняет стек функций?

ответ

0

Это не имеет ничего общего ни с чем, кроме того, что присваивание изменяет переменную, а переменные передаются по значению. tap не имеет значения, поведение идентично, если вы поместите строку в любой переменной.

В вашем случае вы передаете строковый литерал в proc, который получает переменную с именем res, содержащую копию этой строки. Затем вы изменяете эту переменную, , а не оригинальную строку.

Рассмотрим:

def test(res) 
    res += "bar" 
end 

x = "foo" 
test(x) 
puts x # outputs "foo", not "foobar" 

Причина ваш первый пример работы является то, что вы заменить значение в строке res с новым значением. Вы фактически не добавляете данные в строку, хранящуюся в res.

+1

'String's in Ruby очень изменчивы. Существует тонна методов мутаций на 'String':' << ',' [] = ',' clear', 'concat',' prepend', 'setbyte',' force_encoding', 'insert',' replace' , 'sub!', 'gsub!', 'capize!', 'chomp!', 'chop!', 'delete!', 'downcase!', 'upcase!', 'encode!', 'lstrip!' , 'strip!', 'next!', 'succ!', 'reverse!', 'scrub!', 'rstrip!', 'slice!', 'squeeze!', 'swapcase!', 'tr!' , 'tr_s!'. –

+0

Строки не являются неизменяемыми, однако в любое время, когда вы используете оператор присваивания, вы фактически изменяете тот объект, к которому относится левая сторона символа '=', а не изменение значения этого объекта. –

 Смежные вопросы

  • Нет связанных вопросов^_^