lua报错,看到报错信息有tail call,以为和尾调用有关,于是查了一下相关知识

时间:2023-03-08 17:36:29
lua报错,看到报错信息有tail call,以为和尾调用有关,于是查了一下相关知识

  尾调用是指在函数return时直接将被调函数的返回值作为调用函数的返回值返回,尾调用在很多语言中都可以被编译器优化, 基本都是直接复用旧的执行栈, 不用再创建新的栈帧, 原理上其实也很简单, 因为尾调用在本质上看的话,是整个子过程调用的最后执行语句, 所以之前的栈帧的内容已经不再需要, 完全可以被复用。报错的回溯日记,因为旧的执行栈已经没了,所以报错日记只显示(tail call)。一般调用栈的长度为1M到2M,保存了调用过程中的参数和相关环境,如果递归调用太长,就会溢出。尾调用就能解决递归函数带来的问题。

  当时我还怀疑了闭包会不会产生溢出的问题。我觉得闭包的upvalue最后会复制一份放在另一块内存,而不会继续放在调用栈内,所以不会导致溢出,最多就是导致内存泄漏。后来发现闭包的upvalue有一个限制,就是同一个闭包内upvalue的数量不能超过255个。

  我所遇到的问题显然和尾调用,闭包都没关系,我再继续看报错日记,最后的日记是 attempt to perform arithmetic on field '?' is a nil value。我晕,on field '?'是啥意思。

  如果: local aa = {y=2,z=3}

      local dd = aa.x + 1

  就会报 attempt to perform arithmetic on field 'x' is a nil value 因为x确实是nil值。那么,'?'代表什么的,后来发现是数组下标出错。

  如果:lcoal test = {1,2,3,4,5}

     lcoal ret = test [9] + 10

  此时就会报 attempt to perform arithmetic on field '?' is a nil value 因为数组越界了。