- The entry point of any application must be a
func main()function, and it must be within thepackage main.
sayGreeting("Hello", "Daniel")
func sayGreeting(greeting string, name string) {
fmt.Println(greeting, name)
}
// If all arguments have the same type, it can be put only once
func sayGreeting(greeting, name string) {
fmt.Println(greeting, name)
}- Passing pointers instead of values allows the function to modify the contents of the variables.
- Additionally, passing pointers to large data structures is a lot more efficient because it doesn't require the data to be copied across.
- When using
slicesormaps, the pointers are passed automatically!
func sayGreetingPointer(greeting string, name *string) {
fmt.Println(greeting, *name)
*name = "Dani"
}
name := "Daniel"
sayGreetingPointer("Hello", &name)
fmt.Println(name) // "Dani"We can request any number of parameters as the last parameter of a function. The function still allows for other arguments, and the variatic parameters have to be the same type. There can only be one of these.
func sum(msg string, values ...int) int {
fmt.Println(msg, values)
result := 0
for _, v := range values {
result += v
}
return result
}Some rare features of Go functions:
- Can return a local variable by reference. When Go recognises you want to do this, it stores the variable in the
heapinstead of thestack, so that the memory is not deallocated after the function returns.
func sumRef(values ...int) *int {
result := 0
for _, v := range values {
result += v
}
return &result
}
fmt.Println(sumRef(1, 2, 3)) // 0xc000282210
fmt.Println(*sumRef(1, 2, 3)) // 6- Named return values: A variable is declared for you and then returned automatically. It is available within the scope of the function.
func sumNamedReturn(values ...int) (result int) {
for _, v := range values {
result += v
}
return
}- Multiple return values: Quite useful in Go, since Go reserves
paniccalls to severe cases where the app cannot continue, whereas in most cases, there is a better course of action. For example, in a division by zero.
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0.0, fmt.Errorf("Cannot divide by zero!")
}
return a/b, nil
}
d, err = divide(10.0, 0.0)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(d)Although anonymous functions have access to all the variables of the scope where they are declared, usually, it is a better idea to pass the values they need as arguments. This way, we avoid problems when working asynchronously.
func() {
fmt.Println("Hello Go!")
}()
for i := 0; i < 5; i++ {
func(i int) {
fmt.Println(i)
}(i)
}Similar to Python's lambda functions, we can store functions in variables in Go.
f := func() {
fmt.Println("Hello Go!")
}
f()The type of functions is func(). They can also be declared explicitly as follows:
var f func() = func() {
// Do something.
}- These are functions that are called on an object to perform an action on itself. They are like class methods in other languages.
- To declare such a function, we just need to use the following syntax:
func (x type) funcName {}orfunc (x *type) funcName {}. - They can't be declared inside a function, since they're a non-anonymous function.
- By default, the function does create a copy of the object (
valuereceiver), so it can't modify it. - However, we can also make it a
pointerreceiver to be able to change the original object.
type greeter struct {
greeting string
name string
}
func (g greeter) greet() {
fmt.Println(g.greeting, g.name)
g.name = "Dan" // This won't have any effect.
}
func (g *greeter) greetAndChange() {
fmt.Println(g.greeting, g.name)
g.name = "Dan"
}
func main() {
g := greeter{
greeting: "Hello",
name: "Daniel",
}
g.greet()
fmt.Println(g.name)
g.greetAndChange()
fmt.Println(g.name)
}