2010-09-12 27 views
9

Arkadaşlarım ve ben dil için bir fikir edinmek için bazı temel Ruby egzersizleri üzerinde çalışıyoruz ve henüz anlayamadığımız ilginç bir davranışla karşılaştık. Temel olarak, sadece bir değer ve nodes sıfır veya daha fazla bir dizi içeren sadece bir sınıf, node, orada bir tree veri türü oluşturuyoruz. rspec 'un autospec test çalıştırıcısını kullanıyoruz. Bir noktada sonsuz yinelemeye izin vermek için testler yazmaya başladık (yuvarlak bir ağaç yapısı). Çünkü sürekli olarak gerektiği, Biz testin son satırı yığını taşmaları kadar sonsuz özyineleme yol bekliyoruzBu özyineleme neden sonsuz değil?

class Node 
    attr_accessor :value 
    attr_reader :nodes 

    def initialize initial_value = nil 
    @value = initial_value 
    @nodes = [] 
    end 

    def add_child child 
    @nodes.push child 
    @nodes.sort! { |node1, node2| node1.value <=> node2.value } 
    end 

    def == node 
    return (@value == node.value) && (@nodes == node.nodes) 
    end 
end 

: Burada

it "breaks on a circular reference, which we will fix later" do 
    tree1 = Node.new 1 
    tree2 = Node.new 1 
    tree2.add_child tree1 
    tree1.add_child tree2 
    (tree1 == tree2).should be_false 
end 

Düğüm sınıfı var: Burada

test var Çocuk düğümlerini birbiriyle karşılaştırır ve asla bir yaprak düğümü bulamaz. (Dizideki == operatörünün dizinin üzerinde yineleyeceği ve the array page of RubyDoc temel alınarak her bir çocuk için == numaralı telefonu arayacağı izlenimine sahibiz.) Ancak, ne sıklıkta görüldüğünü görmek için puts yöntemini == yöntemine atarsak Tam olarak üç kez denir ve sonra test geçer.

Neler eksik?

Düzenleme: Biz be_true ile testte be_false yerine o zaman Test başarısız olduğunu unutmayın. Bu yüzden dizilerin eşit olmadığına kesinlikle inanıyor, sadece üzerlerinde yineleme yapmıyor (=='a yapılan üç ayrı çağrıdan başka).

+0

@beavis: "==" bu uygulamada yinelemeli, çünkü çocuklarını birbiriyle karşılaştırarak, çocuklarını birbiriyle karşılaştıran iki düğümün çocuklarını karşılaştırmaya çalışıyor. Bu bir "ağaç" çünkü çocuk düğümleri olan bir düğüm var, bu da çocuk düğümlerine sahip olabilir. Bkz. Http://en.wikipedia.org/wiki/Tree_(computer_science) – David

+0

Oldukça dağınık bir ağaç. Bir düğüm, içinde yaşadığı herhangi bir veri yapısının içinde kendini nasıl düzenleyeceğini bilmemeli. – user370731

+0

@beavis: Bu türden mi bahsediyorsunuz? Bu, dizi sıralamasını test etmek için eklediğimiz bir şeydi ve muhtemelen kod olgunlaştıkça silinecek. Aslında her şey için kullanılmayacak olan erken bir prototip. Dediğim gibi, bu noktada dil için bir şeyler hissediyoruz. – David

cevap

7

Eğer bağlı RubyDoc yöntemi adını tıklarsanız Array#== yöntemin (C) kaynağını göreceksiniz:

{ 
    // [...] 
    if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; 
    if (rb_inspecting_p(ary1)) return Qfalse; 
    return rb_protect_inspect(recursive_equal, ary1, ary2); 
} 

Bu uygulama (özellikle "recursive_equal") düşündürmektedir Array#== zaten sınırsız özyineleme koruması uygular.

+0

Ah, öyle. Teknik olarak şu anki korumamız, nihayetinde veri türümüze izin verilmesini engellemektir, ancak bu add_child yöntemi için bir şeydir. Sanırım hiç bir zaman sessizce dönüp bir çeşit hata yapmamamızın asla gerçekleşmediğini sanıyordum. Her şey dile alışmanın bir parçası, sanırım. Merak etme, sessiz dönüşün sebebini biliyor musun? (Şüphesiz, ben C dilinde çok iyi bilmiyorum, bu yüzden bu uygulamadan sonra sadece belli belirsiz.) – David

+1

Benim C ya da harika değil, ama önceki satırın 'if (rb_inspecting_p (ary1)) Qfalse döndürdüğü; 'aslında 'sessiz' yanlış dönüşü tetikleyen şeydir. Temelde, "ary1" in herhangi bir noktasında * ary1 ile karşılaşırsak yanlış geri döner gibi görünüyor. – Gareth

+0

@Gareth: Anlam veriyor. Bu uygulamaların o sitede bağlantılı olduğunu bile bilmiyordum.Bu bizim çabalarımızda bize yardımcı olacak (aynı zamanda C'yi okuma konusunda biraz daha fazla fırçalayacak). Bu kontrolü bildiğim için, kontrol edilmesi kolay, ki bu da add_child yönteminde kullanışlı olacak. – David