1

我正在研究我的编程语言,它可以编译成 bash 4.3+ 代码。我正处于语言的最后阶段,但我对递归函数有一个小问题。这是 bash 代码,它应该返回给定索引的斐波那契数。

#!/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 -nnamerefs 找到解决方案。

谢谢

4

1 回答 1

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
于 2017-06-15T20:04:21.247 回答