我正在编写我的编程语言,它编译成bash 4.3+代码。我处于语言的最后阶段,但我对递归函数有一个小问题。这是bash代码,它应该返回给定索引的fibnacci数。
#!/bin/bash
function fib() {
local a=$1
declare -n ret=$2
if (( $a <= 2 )); then
ret=1
return
fi
fib $((a-1)) fib1
fib $((a-2)) fib2
ret=$((fib1+fib2))
echo "fib($((a-1))) + fib($((a-2))) = $ret"
return
}
num=5
fib $num result
echo
echo "fib($num) = $result"
此代码中的问题是fib(5)给出3这显然是错误的。我认为问题是,当我传递fib1和fib2作为存储返回值的方法时,它们会被分配它们的每个调用覆盖。如果这是问题所在,我如何将fib1
和fib2
置于执行范围内。
请注意,我不想使用return
语句来返回值,我想尝试使用declare -n
namerefs找到解决方案。
谢谢
答案 0 :(得分:1)
我认为问题是,当我传递fib1和fib2作为存储返回值的方法时,它们会被分配它们的每个调用覆盖。
是的,您可以通过在递归调用之间和之后打印fib1
的值来看到:
fib $((a-1)) fib1
echo "fib($a): fib1: $fib1"
fib $((a-2)) fib2
echo "fib($a): fib1: $fib1 fib2: $fib2"
您应该会在第二次通话中看到fib1
的值发生变化。这是预期的,因为它没有被声明local
并且只有一个fib1
的全局副本。
如果你把它们当作本地......它没有多大帮助。
假设您首先致电fib 4 result
。第一次迭代将使fib1
为本地,并调用fib 3 fib1
。现在第二次迭代也会使fib1
为本地,但它也会尝试将其返回值赋给同名的变量。由于访问是按名称进行的,因此会将返回值保存到fib1
的自己的副本。
这可以通过一个稍微简单的脚本来看,它试图从递归的底部返回一个固定的值:
#!/bin/bash
foo() {
declare -n ret=$2
if (( $1 == 0 )); then
echo "foo($1) returning"
ret=end # this is the value that should bubble up
return
fi
local x=initial$1 # use $1 here to track the level the value came from
foo $(($1 - 1)) x
ret=$x
echo "foo($1) = $x"
return
}
foo 3 result
echo "main: $result"
我能想到的解决方法是为返回值设置一个单独的全局变量,并立即将其复制到局部变量:
local fib1 fib2
fib $((a-1)) retval
fib1=$retval
fib $((a-2)) retval
fib2=$retval