Shubham Chaudhary
Shubham Chaudhary

Reputation: 1472

Running a statement only on outermost function of recursion in Golang

I have a recursive function and I want one execute some statement only for the outermost call to the function. How do I achieve this functionality?

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

This should print only 4

Upvotes: 0

Views: 341

Answers (4)

leaf bebop
leaf bebop

Reputation: 8212

To answer the question itself: if for some reason you really want to run something that is only for outermost func call and don't want to change api, Golang has a runtime lib for that. You may do it as:

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

playground: https://play.golang.org/p/ro1ZOn6yIR7 It is no good practice, but solve the question most straightfowardly.

Note: Use a global variable is very likely to cause glitches. You need to set it every time you call the func, and if there is concurency, data race would be involved.

And if you are unconfortable with the fact that the extra bool argument get allocated every recursive call (which could be countless time), you may look at @Adrian 's answer or wrap it as a method of a bool.

Upvotes: 1

Adrian
Adrian

Reputation: 46413

A simple anonymous function is probably the cleanest, as it does not add a parameter, complicating the API for external callers just to implement internal logic.

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
}

This achieves the same functionality, but the caller doesn't have to know to pass an additional bool or int value that's irrelevant to it. Full example here: https://play.golang.org/p/7vHwPDN2_FL

Upvotes: 1

abhink
abhink

Reputation: 9116

Answer to edited question:

You can use he second pattern below again:

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

Again, you can use closures or helper functions to clean this up.

Original answer:

Try using a global variable:

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

There are other ways to achieve this. For example, you can use similar technique with closures as well. Or add another parameter to 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)
}

Upvotes: 1

Marc
Marc

Reputation: 21035

You could pass something like a depth that gets incremented at each call. Eg:

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

If this is really your use case, you're much better off doing:

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

Upvotes: 1

Related Questions