1

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


アップデート

すべての回答に感謝しますが、残念ながら、実際に何が起こっているのかまだわかりません。正しく理解すれば、バケツのようなものです。何かを入れるたびに、それは処理されています。そして、'loop do' は、そこに入れられたバイトの数だけ実行されます。

関数は次のように 1 回だけ呼び出されます。

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

しかし、これも列挙子の内部にあるため、バイトが一方のバケットから他方のバケットに滴り落ちていると思います。

いかなる場合でも。関数を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::Yielderyieldメソッドは としてエイリアス化されてい<<ます。だから呼び出す:

yielder << some_byte

以下と同じです:

yielder.yield some_byte

呼び出しyieldは制御フローをブロックします。nextEnumerator オブジェクトで (または同等の c 関数) が呼び出されたときに、制御を返すことができます。が呼び出されない場合next、ループは続行されず、列挙子がスコープから外れてガベージ コレクションされるまで、その状態のままになります。

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 に答える