An overview about: anonymous, higher-order, closures, concurrent, deferred, and other kinds of Golang funcs. This post is a summary for the different kind of funcs in Go. I’ll go into more detail in the upcoming posts because they deserve more. This is just a start. What is a function? A function is a separate and reusable block of code which can be runned again and again. Functions may accept input values and they may return output values. Why do we need functions? Increasing the readability, testability and maintainability Making some part of a code separately executable Composing things from smaller things Adding behavior to types Organizing the code To be DRY Named Funcs A named func has a name and declared at the package-level — . outside of the body of another func 👉 I explained them in detail in my another post, here . This is a named func: Len func takes a string and returns and int Variadic funcs A variadic func accepts variable number of input values — zero or more. Ellipsis (three-dots) prefix in front of an input type makes a func variadic. Declares a variadic func with a variadic input param of strings named as `names`. Example Let’s create a Logger which the verbosity and the prefix options can be changed at the run-time using the option pattern: type Logger struct { verbosity prefix string } SetOptions applies options to the Logger to change its behavior using a variadic option param: func (lo *Logger) SetOptions(opts ...option) { for _, applyOptTo := range opts { applyOptTo(lo) } } Let’s create some funcs which return option func as a result in a closure to change the Logger’s behavior: func HighVerbosity() option { return func(lo *Logger) { lo.verbosity = High } } func Prefix(s string) option { return func(lo *Logger) { lo.prefix = s } } Now, let’s create a new Logger with the default options: logger := &Logger{} Then provide options to the logger through the variadic param: logger.SetOptions( HighVerbosity(), Prefix("ZOMBIE CONTROL"), ) Now let’s check the output: logger.Critical("zombie outbreak!") // [ZOMBIE CONTROL] CRITICAL: zombie outbreak! logger.Info("1 second passed") // [ZOMBIE CONTROL] INFO: 1 second passed See the working code with the explanations inside 👉 To learn more about them check out my post about variadic funcs, here . Methods When you attach a func to a type the func becomes a of that type. So, it can be called through that type. Go will pass the type ( to the method when it’s called. method the receiver) Example Create a new counter type and attach a method to it: type Count int func (c Count) Incr() int { c = c + 1 return int(c) } The method above is similar to this func: func Incr(c Count) int Not exactly true but you can think of the methods as above Value receiver The value of the Count instance is copied and passed to the method when it’s called. var c Count; c.Incr(); c.Incr() // output: 1 1 It doesn’t increase because “c” is a value-receiver. Pointer receiver To increase the counter’s value you need to attach to — *Count. the Incr func the Count pointer type func (c *Count) Incr() int { *c = *c + 1 return int(*c) } var c Count c.Incr(); c.Incr() // output: 1 2 There are more examples from my previous posts: and . here here Interface methods Let’s recreate the above program using the interface methods. Let’s create a new interface named as : Counter type Counter interface { Incr() int } onApiHit func below can use any type which has an method: Incr() int func onApiHit(c Counter) { c.Incr() } Just use our dummy counter for now — : you can use a real api counter as well dummyCounter := Count(0) onApiHit(&dummyCounter) // dummyCounter = 1 Because, the Count type has the Incr() int method on its method list, onApiHit func can use it to increase the counter — I passed a pointer of dummyCounter to onApiHit, otherwise it wouldn’t increase the counter. The difference between the interface methods and the ordinary methods is that the interfaces are much more flexible and loosely-coupled. You can switch to different implementations across packages without changing any code inside onApiHit etc. First-class funcs First-class means that funcs are value objects just like any other values which can be stored and passed around. Funcs can be used with other types as a value and vice-versa Example: The sample program here processes a sequence of numbers by using a slice of as an input param value to a func named “ ”. Crunchers crunch Declare a new “ ” which takes an int and returns an int. user-defined func type : This means that any code that uses this type accepts a func with this exact signature type Cruncher func(int) int Declare a few cruncher funcs: func mul(n int) int { return n * 2 } func add(n int) int { return n + 100 } func sub(n int) int { return n - 1 } Crunch func processes a series of ints using : a variadic Cruncher funcs func crunch(nums []int, a ...Cruncher) (rnums []int) { // create an identical slice rnums = append(rnums, nums...) for _, f := range a { for i, n := range rnums { rnums[i] = f(n) } } return } Declare an int slice with some numbers and process them: nums := []int{1, 2, 3, 4, 5} crunch(nums, mul, add, sub) Output: [101 103 105 107 109] Anonymous funcs A noname func is an anonymous func and it’s declared inline using . It becomes more useful when it’s used as a closure, higher-order func, deferred func, etc. a function literal Signature A named func: func Bang(energy int) time.Duration An anonymous func: func(energy int) time.Duration They both have the same signature, so they can be used interchangeably: func(int) time.Duration Example Let’s recreate the cruncher program from using the anonymous funcs. Declare the crunchers as anonymous funcs inside the main func. the First-Class Funcs section above func main() { crunch(nums, func(n int) int { return n * 2 }, func(n int) int { return n + 100 }, func(n int) int { return n - 1 }) } This works because, crunch func only expects the Cruncher func type, it doesn’t care that they’re named or anonymous funcs. To increase the readability you can also assign them to variables before passing to crunch func: mul := func(n int) int { return n * 2 } add := func(n int) int { return n + 100 } sub := func(n int) int { return n - 1 } crunch(nums, mul, add, sub) Higher-Order funcs An higher order func may take one or more funcs or it may return one or more funcs. Basically, it uses other funcs to do its work. Split func in the closures section below is a higher-order func. It returns a as a result. tokenizer func type Closures A closure can remember all the surrounding values where it’s defined. One of the benefits of a closure is that it can operate on the captured environment as long as you want — beware the leaks! Example Declare a new func type that returns the next word in a splitted string: type tokenizer func() (token string, ok bool) Split func below is which splits a string by a separator and returns a which enables to walk over the words of the splitted string. an higher-order func closure The returned closure can use the surrounding variables: “tokens” and “last”. Let’s try: const sentence = "The quick brown fox jumps over the lazy dog" iter := split(sentence, " ") for { token, ok := iter() if !ok { break } fmt.Println(token) } Here, we use the split func to split the sentence into words and then get and put it into the iter variable. a new iterator func as a result value Then, we start an infinite loop which terminates only when the iter func returns false. Each call to the iter func returns the next word. The result: The quick brown fox jumps over the lazy dog Again, more explanations are inside. Deferred funcs A deferred func is only executed after its parent func returns. Multiple defers can be used as well, they run as a , one by one. stack Example Go runtime will save any passed params to the deferred func at the time of registering the defer — . not when it runs Declare a dummy func that registers a deferred closure. : It also uses a named result value “n” to increase the passed number for the second time func count(i int) (n int) { defer func() { n = n + i }(i) i = i * 2 n = i return } Let’s try: count(10) // output: 30 What happened? Parse the visual following the numbers (on the left): 1, 2, 3 . In some situations defer can help you to change the result value before the return by using the named result values as seen in the example. 👉 To learn more about them check out my post about Go defers, here . Concurrent funcs go func() runs the passed func concurrently with the other goroutines. A goroutine is a lighter thread mechanism which allows you to structure concurrent programs efficiently. The main func executes in the main-goroutine. Example Here, “start” anonymous func becomes a concurrent func that doesn’t block its parent func’s execution when called with “go” keyword: start := func() { time.Sleep(2 * time.Second) fmt.Println("concurrent func: ends") } go start() fmt.Println("main: continues...") time.Sleep(5 * time.Second) fmt.Println("main: ends") Output main: continues... concurrent func: ends main: ends Main func would terminate without waiting for the concurrent func to finish if there were no sleep call in the main func: main: continues... main: ends Other Types Recursive funcs You can use recursive funcs as in any other langs, there is no real practical difference in Go. However, you must not forget that each call creates a new . But, in Go, stacks are dynamic, they can shrink and grow depending on the needs of a func. If you can solve the problem at hand without a recursion prefer that instead. call stack Black hole funcs A black hole func can be defined multiple times and they can’t be called in the usual ways. They’re sometimes useful to test a parser: see . this func _() {} func _() {} Inlined funcs Go linker places a func into an executable to be able to call it later at the run-time. Sometimes calling a func is an expensive operation compared to executing the code directly. So, the compiler injects func’s body into the caller. To learn more about them: Read and and and . this this this this External funcs If you omit the func’s body and only declare its signature, the linker will try to find it in an external func that may have written elsewhere. As an example, just declared with a signature and then . Atan func here implemented in here 💓 Share this post with your friends. Thank you! 💓 I’m also creating an online course for Go → ← Join to my newsletter “ Let’s stay in touch weekly for new tutorials and tips “ Read more: 🐣 Go Funcs — Baby-Gopher’s Visual Guide Originally published at blog.learngoprogramming.com on November 9, 2017.