6

When to use functioneExpression rather than function declaration in Go?

I searched Function Expression vs Function Declaration (in JS), it's about hoisting. How about Golang?

icza
  • 389,944
  • 63
  • 907
  • 827
Yosua Lijanto Binar
  • 670
  • 1
  • 8
  • 27
  • If there is a package-wide variable or function declared, it can be used anywhere else in the package (and outside the package if it's exported), even if you use it before it's declared. However, the specifics of JavaScript hoisting don't apply to Go. – Gavin Sep 20 '17 at 13:29
  • @Gavin Your explanation is great, but does it have same functionality like function declaration? – Yosua Lijanto Binar Sep 20 '17 at 13:42

2 Answers2

7

There is one unique property to each:

  • A function declaration binds an identifier, the function name, to a function; so the function name will be an identifier which you can refer to.

  • A function literals represents an anonymous function. Function literals are closures, they capture the surrounding environment: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.

Don't be deluded: syntactically whenever a function literal is used, a declared function could also be used. For example the following code is a valid and working Go code:

func do() {}

func main() {
    go do()
    defer do()
}

The answer to when to use one over the other lies in the unique properties listed above.

Use function declaration when you want to refer to the function, when you want to reuse it. This is also a good way to separate code, function declaration must be at the file level: you can't declare a function in another function. See Golang nested class inside function for details.

Use function literals when you want the function to have access to the local variables and other identifiers surrounding it. Since you can't declare a function in another function, to capture the local variables and identifiers, the only option here is a function literal (unless you want to pass everything as arguments to a declared function, which could quickly get dirty if the function needs to modify the values in which case they need to be "transformed" into pointers and addresses need to be passed). For an interesting related question, check out Define a recursive function within a function in Go.

When the function does not need to have a name, and the function does not need access to the local variables, you may choose which one to use, relying on your judgement, examples seen in other (quality) projects and prior experiences. If the function body is "small", easier / simpler to use a function literal. If the function body is "big", code will be easier to read and understand if you declare it as a separate function and provide sufficient documentation to it.

An interesting / related topic is a variable of function type, which you may initialize using either a function literal or with a declared function. It has the benefits that it is an identifier so you can refer to it, and that its value can be changed and a new function can be assigned to it.

For example:

func do() { fmt.Println("Doing...") }

var f = do

func main() {
    f()
    f = func() { fmt.Println("Not doing!") }
    f()
}

Output of the above (try it on the Go Playground):

Doing...
Not doing!

Very useful for mocking functions in tests. For an example, see Testing os.Exit scenarios in Go with coverage information (coveralls.io/Goveralls).

icza
  • 389,944
  • 63
  • 907
  • 827
5

Anonymous functions in Go are used in various situations:

- to start a goroutine

go func() {
    // body
}()

- with a defer statement

defer func() {
    // body
}()

- as an argument to another function

err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
    // todo
})

- as a closure (examples)

Function declarations are used when you want to refer to the function by name. Maybe to call it from multiple places in your own code, or to expose it to other packages.

dev.bmax
  • 8,998
  • 3
  • 30
  • 41