这个'循环'如何结束?

时间:2013-04-03 20:56:04

标签: ruby

我正在将github.com上的一段Ruby代码重写为Javascript。除了以下部分之外,我对理解代码没有任何问题。问题是:'循环如何做'如果没有“休息”结束?

  def utf8_bytes(record_size, record_tag)
    Enumerator.new do |yielder|
      bits = compressed_bits record_size, record_tag
      loop do
        # Use the Huffman tree to decode the first character.
        node = tree_root
        while node < 0x100
          # p ['node', node]
          bit = bits.next
          # p ['bit', bit]
          node = (bit == 0) ? tree_left[node] : tree_right[node]
        end
        first_byte = node - 0x100
        # p ['utf8 start', first_byte]
        yielder << first_byte

        # The other characters are 10xxxxxx, where x'es are raw bits.
        2.upto utf8_char_bytes(first_byte) do
          byte = 0b10
          6.times do
            byte = (byte << 1) | bits.next
          end
          # p ['utf8 byte', byte]
          yielder << byte
        end
      end
    end
  end


更新

感谢所有的答案,但不幸的是我仍然不明白真正发生的事情。如果我理解正确,它就像一个桶。每当你把东西放入其中时,它就会被处理掉。并且&#39;循环做&#39;完成的次数与放入的字节数相同。

该函数只调用一次,如下所示:

  text = utf8_bytes(record_size, record_tag).to_a.pack('C*')

但这也是在Enumerator中,所以我猜这些字节从一个桶流入另一个桶。

无论如何。我已将该功能翻译成Javascript。也许有人可以告诉我这是否正确? (撇开Javascript函数返回一个数组,除了使用这样的数组可能效率不高)

    function utf8_bytes( record_size, record_tag ) {
        var yielder = new Array();
        bits = compressed_bits( record_size, record_tag );
// compressed_bits returns an array of 0's and 1's
        var v=0;
        while( v<bits.length ) {
//              # Use the Huffman tree to decode the first character.
            var node = tree_root;
            while ( node < 0x100 ) {
//                  # p ['node', node]
                bit = bits[v++];
//                  # p ['bit', bit]
                node = (bit == 0) ? tree_left[node] : tree_right[node];
            }
            var first_byte = node - 0x100;
//              # p ['utf8 start', first_byte]
            yielder.push( first_byte );

//              # The other characters are 10xxxxxx, where x'es are raw bits.
            for (var m=2; m<=utf8_char_bytes(first_byte); m++ ){
                var mbyte = 2;
                for (var n=0; n<6; n++ ) {
                    mbyte = (mbyte << 1) | bits[v++];
                }
//                  # p ['utf8 byte', mbyte]
                yielder.push( mbyte );
            }
        }
        return( yielder );
    }

3 个答案:

答案 0 :(得分:1)

它似乎是一个枚举器(请注意Enumerator.new do |yielder|。)我的猜测是每次追加运算符(<<)应用于yielder时控制流返回。

答案 1 :(得分:1)

Enumerator::Yielder中,yield方法的别名为<<。所以打电话:

yielder << some_byte

与:

相同
yielder.yield some_byte

调用yield会阻止控制流程。在Enumerator对象上调用next(或等效的c函数)时,控件可以返回。如果永远不会调用next,则循环将不会继续,并且将保持该状态,直到Enumerator超出范围并被垃圾收集。

您可以阅读Enumerator课程了解更多信息。

答案 2 :(得分:0)

循环永远不会自行结束,即此方法返回无限枚举器。

utf8_bytes(...).to_a # => never ends

这些非常有用,因为你调用它们的块可以在使用整个(无限)枚举器之前返回:

def foo
  utf8_bytes(...).each do |byte|
    return byte if is_it_what_youre_looking_for?(byte)
  end
  # You'll never get here!
end

以类似的方式,只获得几个值是有用的。例如:

utf8_bytes(...).first(100) # => array of length 100

要使用更简单的“无限”枚举器,您可以使用0..Float::INFINITY而不是调用utf8_bytes