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

问题描述 投票:0回答:4

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

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

go
4个回答
1
投票

要回答问题本身:如果由于某种原因你真的想要运行仅用于最外层func调用并且不想更改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)
}

操场:qazxsw poi这不是一个好习惯,但最直接地解决问题。

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

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


1
投票

你可以传递像https://play.golang.org/p/ro1ZOn6yIR7这样的东西,在每次通话时都会增加。例如:

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)
}

1
投票

回答编辑过的问题:

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

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

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

原始答案:

尝试使用全局变量:

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

1
投票

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

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)
}

这实现了相同的功能,但调用者不必知道传递与其无关的额外bool或int值。这里有完整的例子: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 }

© www.soinside.com 2019 - 2024. All rights reserved.