递归函数不返回任何值

时间:2016-12-20 14:13:24

标签: php recursion factorial

我想了解为什么这个函数不会返回任何内容。

function fact($n, $p = 1) {
    if ($n > 1) {
        $p *= $n--;
        fact($n, $p);
    } else {
        return $p;
    }
}

var_dump(fact(5)); // NULL

4 个答案:

答案 0 :(得分:3)

因为如果Activesheet.Range(ActiveSheet.PageSetup.PrintArea).Select 条件为Activesheet.Range(ActiveSheet.PageSetup.PrintArea).CheckSpelling ,则不会遇到if语句。也许你的意思是:

true

答案 1 :(得分:3)

您尝试分配一个未通过引用传递的变量。通过引用传递$ p(&$p)或使用返回值。在这种情况下,返回值更好。

其次,$n--是后递减,意味着你的代码读得不好。

function fact($n) {
    if ($n == 0) return 1;
    return $n * fact($n - 1);
}

var_dump(fact(5))

答案 2 :(得分:2)

递归是一种来自函数式语言的循环结构。是的,正如其他人所说,你的函数无法正常工作,因为if语句的 true 分支并没有返回任何内容。但是,我还有关于您的代码的其他评论

function fact($n, $p = 1) {
    if ($n > 1) {
        // this makes it hard to reason about your code
        $p *= $n--;
        return fact($n, $p);
    } else {
        return $p;
    }
}

您实际上在一个表达式中突变两个变量。如果您试图让代码看起来更短,那就很聪明,但实际上还有更好的方法。

function fact($n, $p = 1) {
    if ($n > 1) {
        $p *= $n--;
        // just compute the next values; no need to update $p or $n
        return fact($n - 1, $p * $n);
    } else {
        return $p;
    }
}

现在我们不必考虑$p$n单独变化的方式。我们只知道我们再次使用下一个值为fact$p的每个州调用$n

请记住,在某些函数式编程语言中,这些原则非常强大,甚至不允许重新分配像$p$n这样的变量。

最后,我们必须讨论您的API泄漏问题$p。如果有人在调用fact时指定了一个值,他们可能会得到错误的答案或触发错误

// bad !
fact(5, 10); // => 1200

这是唯一可行的,因为$p实际上是在公共API中公开的。要解决这个问题,你有几个选择

其中一个是像@RonaldSwets建议的那样:

function fact($n) {
    // 1 is the base case, like you had for $p in your code
    if ($n == 0)
      return 1;
    // otherwise return $n times the next value
    else
      return $n * fact($n - 1);
}

另一种方法是使用仅供私人使用的辅助功能

// function used by `fact`
function fact_aux ($n, $p) { 
  if ($n == 0)
    return $p;
  else
    return fact_aux($n - 1, $p * $n);
}

// function meant to be used by others
function fact ($n) {
  return fact_aux($n, 1);
}

答案 3 :(得分:1)

你的事实只在' Loop through the list of table definitions. For Each tblRep In dbRep.TableDefs Set rec1 = dbRep.OpenRecordset("SELECT MSysObjects.Name FROM MsysObjects WHERE ([Name] = '" & tblRep.Name & "') AND ((MSysObjects.Type)=4 or (MSysObjects.Type)=6)") If rec1.EOF Then XF = 0 Else XF = 1 End If ' Ignore system tables and CMDB tables. If InStr(1, tblRep.Name, "MSys", vbTextCompare) = 0 And _ InStr(1, tblRep.Name, "CMDB", vbTextCompare) = 0 And _ XF = 0 Then ' Open a recordset for the new table. Set rstNew = dbNew.OpenRecordset(tblRep.Name, dbOpenTable) ' Open a recordset for the old table. Set rstRep = dbRep.OpenRecordset(tblRep.Name, dbOpenTable) ' Continue if there are records. If Not rstRep.BOF Then ' Move to the first record. rstRep.MoveFirst ' Loop through all the old table records. Do Until rstRep.EOF ' Add a record to the new table. rstNew.AddNew ' For each field in the new table, set the value ' to the value in the related field of the old table. For intC = 0 To rstNew.Fields.count - 1 rstNew.Fields(intC).Value = _ rstRep.Fields(rstNew.Fields(intC).Name).Value Next ' Update the new table. rstNew.Update ' Move to the next old table record. rstRep.MoveNext Loop ' rstRep End If ' Close the new recordset. rstNew.Close ' Close the old recordset. rstRep.Close End If Next tblRep 时返回值。在$n == 1时,您必须在$n > 1中返回值fact(n-1)