我正在将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 );
}
答案 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
。