1

我正在将 github.com 上的一段 Ruby 代码重写为 Javascript。我在理解代码时没有任何问题,除了下面的部分。问题是:如果没有“break”,“loop do”如何结束?

  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


更新

感谢所有的答案,但不幸的是我仍然不明白到底发生了什么。如果我理解正确的话,它就像一个水桶。每次你把东西放进去,它都在被处理。并且“循环执行”的次数与放入其中的字节数一样多。

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

  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 );
    }
4

3 回答 3

1

Enumerator::Yielder中,该yield方法别名为<<。所以调用:

yielder << some_byte

是相同的:

yielder.yield some_byte

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

您可以阅读Enumerator课程以获取更多信息。

于 2013-04-03T21:02:24.277 回答
1

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

于 2013-04-03T20:57:46.007 回答
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.

于 2013-04-04T16:50:27.050 回答