仅在Golang中递归的最外层函数上运行语句

时间:2017-12-27 10:33:07

标签: go

我有一个递归函数,我想只为最函数调用执行一些语句。我如何实现此功能?

func fact(n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1)
   if outer_most{
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}
func main() {
  fact(4)
}

这应仅打印4

4 个答案:

答案 0 :(得分:1)

回答编辑过的问题

您可以再次使用下面的第二种模式:

func fact(n int, outerMost bool) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1, false)
   if outerMost {
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}

func main() {
    fact(4, true)
}

同样,您可以使用闭包或辅助函数来清理它。

原始答案:

尝试使用全局变量:

var outerMost bool = true

func fact(n int) int {
    if outerMost {
        fmt.Printf(strconv.Itoa(n))
        outerMost = false
    }
    if n == 0 {
       return 1
    }
    return n * fact(n-1)
}

func main() {
    fact(4)
}

还有其他方法可以实现这一目标。例如,您也可以使用与闭包相似的技术。或者将另一个参数添加到fact

func fact(n int, outerMost bool) int {
    if outerMost {
        fmt.Printf(strconv.Itoa(n))
        outerMost = false
    }
    if n == 0 {
       return 1
    }
    return n * fact(n-1, outerMost)
}

func main() {
    fact(4, true)
}

答案 1 :(得分:1)

您可以传递类似depth的内容,在每次调用时都会增加。例如:

func fact(depth int, n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(depth + 1, n-1)
   if depth == 0 {
       fmt.Println(fact)  // I assume you meant to print fact here.
   }
   return fact 
}
func main() {
  fact(0, 4)
}

如果这确实是你的用例,你做得更好:

func fact(n int) int {
  if n == 0 {
     return 1
  }
  return n * fact(n-1)
}
func main() {
  fmt.Println(fact(4))
}

答案 2 :(得分:1)

一个简单的匿名函数可能是最干净的,因为它不添加参数,使外部调用者的API复杂化只是为了实现内部逻辑。

func fact(n int) int {
    var facto func(n int) int
    facto = func(n int) int {
        if n == 0 {
            return 1
        }
        fact := n * facto(n-1)
        return fact
    }
    n = facto(n)
    fmt.Printf("%d", n)
    return n
}

这实现了相同的功能,但调用者不必知道传递与其无关的额外bool或int值。完整示例:https://play.golang.org/p/7vHwPDN2_FL

答案 3 :(得分:1)

回答问题本身:如果出于某种原因你真的想要运行仅用于最外层函数调用并且不想更改api的东西,那么Golang有一个运行时库。 你可以这样做:

package main

import (
    "fmt"
    "runtime"
    "strconv"
)

func outer_most() bool {
    pc:=make([]uintptr,2)
    runtime.Callers(2,pc) //skip: 1 - runtime.Caller, 2 - outer_most itself
    return runtime.FuncForPC(pc[0])!=runtime.FuncForPC(pc[1]) // test if the caller of the caller is the same func, otherwise it is the outermost
}

func fact(n int) int {
   if n == 0 {
      return 1
   }
   fact := n * fact(n-1)
   if outer_most() {
       fmt.Printf(strconv.Itoa(n))
   }
   return fact 
}

func main() {
  fact(4)
}

游乐场:https://play.golang.org/p/ro1ZOn6yIR7 这不是一个好习惯,但最直接地解决了这个问题。

注意: 使用全局变量很可能会导致故障。每次调用func时都需要设置它,如果有可靠性,则会涉及数据争用。

如果你对每个递归调用(可能是无数次)分配额外bool参数的事实感到不自然,你可以查看@Adrian的答案或将其包装为bool的方法。