我制作了两个阵列,每个阵列有100万个项目:
a1 = 1_000_000.times.to_a
a2 = a1.clone
我试图将a2推入a1:
a1.push *a2
这回来了SystemStackError: stack level too deep.
但是,当我尝试使用时concat,我没有收到错误:
a1.concat a2
a1.length # => 2_000_000
我也没有得到splat运算符的错误:
a3 = [*a1, *a2]
a3.length # => 2_000_000
为什么会这样?我查看了文档Array#push,并用C语言编写.我怀疑它可能是在引擎盖下进行一些递归,这就是为什么它会导致大型数组的这个错误.它是否正确?push用于大型阵列不是一个好主意吗?
Cas*_*per 25
我认为这不是递归错误,而是参数堆栈错误.您正在运行参数的Ruby VM堆栈深度限制.
问题是splat运算符,它作为参数传递给push.splat运算符扩展为百万元素参数列表push.
函数参数作为堆栈元素传递,并且Ruby VM堆栈大小的预配置最大大小为:
RubyVM::DEFAULT_PARAMS[:thread_vm_stack_size]
=> 1048576
..这是限制的来源.
您可以尝试以下方法:
RUBY_THREAD_VM_STACK_SIZE=10000000 ruby array_script.rb
..它会工作正常.
这也是您想要使用的原因concat,因为整个数组可以作为单个引用传递,concat然后在内部处理数组.与push+ splat 相反,它将尝试将堆栈用作所有数组元素的临时存储.