1

私が開発しているRubyアプリケーションがありますが、別のクラスの関数呼び出しから値を返すために内部にブロックを含む再帰関数を使用すると、何らかの理由で期待どおりに機能しません(サンプルコードで見やすくなります)下)。奇妙なことに、何が起こっているのかを調べるために最小限のサンプルを作成したとき、サンプルは期待どおりに機能します。例:

require 'json'

class Simple
    attr_accessor :name, :children

    def initialize(name,children=nil)
        @name = name
        @children = children
    end
end

a = Simple.new('A')
b = Simple.new('B',[a])
c = Simple.new('C',[b])
d = Simple.new('D')
e = Simple.new('E',[d])
f = Simple.new('F')
g = Simple.new('G',[e,f])

foo = [c,e,g]

def looper(d)
    holder = nil

    d.each do |item|
        # puts item.name
        if item.name == 'D'
            holder = Simple.new('Z',[])
        elsif !item.children.nil?
            holder = looper(item.children)
        end
    end

    return holder
end

bar = looper(foo)
puts "Returned from looper: #{bar.name}"

実際のコードでは、クラスインスタンス変数を使用して応答を取得することになりました(これはサンプルコードでも機能します)。上記の関数のスニペットの例を他のパターンに変更しました。

def looper(d)
    holder = nil

    d.each do |item|
        # puts item.name
        if item.name == 'D'
            @holder = Simple.new('Z',[])
        elsif !item.children.nil?
            looper(item.children)
        end
    end

    @holder
end

だから私の質問は、インスタンス変数を使用するのは良い習慣ですか?最初の例のパターンは機能しないのに対し、実際のコードでは機能するので、そうすることの欠点はありますか?

4

1 に答える 1

0

あなたの最初のコードでは、nilあなたの入力から、2番目のバージョンでオブジェクトを取得することを期待していますSimple.new('Z',[])

それがあなたの問題である場合、それはアイテムgに子があるためです.最初のものは値を再帰的に設定しますが、2番目のものは値を設定解除するため、ループの2回目holderはに設定されnilます.

編集:実際には、上の例からの結果の私の分析は間違っています。最上位リストの最後の項目には検索対象の項目が含まれているためです。ただし、問題の分析と 2 つのソリューション間の動作の違いは、一般的には依然として有効です。

あなたはおそらくこれが欲しいだけです:

def looper(d)
    holder = nil

    d.each do |item|
        # puts item.name
        if item.name == 'D'
            holder = Simple.new('Z',[])
            break
        elsif !item.children.nil?
            holder = looper(item.children)
            break if holder
        end
    end

    return holder
end

break ステートメントにより、 に再度代入することができなくなりますholder。. .

#firstあるいは、またはのような Ruby 内部を使用#any?して、検索を表現します。

再帰間の相互通信のために2番目の例に従ってインスタンス変数に割り当てることは問題ありません。再帰の実行中、それらはすべての深さと反復間で効果的に共有されます。そのため、再帰や Ruby 自体が壊れることはありませんが、他の種類の望ましくない相互作用に注意する必要があります: たとえば、インスタンス変数が再帰中に特定の場所に設定されたと想定することはできません。. .

于 2013-03-21T17:24:39.803 に答える