# Basics of `func`tutorial

• If the name begins with an upper-case letter, it is exported(accessible outside of its own package)
• No default parameter values
• No keyword(or named) arguments
• Arguments are passed by value.
• The zero value of a function type is `nil`.
``````func add(x int, y int) int {
return x + y
}

// Declarations of consecutive same type parameters can be coalesced.
func add(x, y int) int {
return x + y
}

// Return values can be named, in which case
// the name declares a local variable initialized to the zero value for its type.
func add(x, y int) (z int) {
z = x + y
return  // this is called 'naked(or bare) return'
}

// Functions can have multiple return values
func addsub(x, y int) (int, int) {
return x + y, x - y
}``````
Deferred functions
``````for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}``````
``````4 3 2 1 0
``````
• Schedules a function call (the deferred function) to be run immediately before the function which executes the defer returns.
• Deferred functions are executed in LIFO order.
• The arguments to the deferred function are evaluated when the defer executes(or registering phase), not when the call executes.
Variadic functions; within the body of the function, the type of `vals` is an `[]int` slice.
``````func sum(vals ...int) int {
total := 0
for _, val := range vals {
total += val
}
return total
}``````
Place `...` after the final argument to call a function with elements of a slice.
``````values := []int{1, 2, 3, 4}
fmt.Println(sum(values...)) // "10"``````
Methods
``````type Point struct{ X, Y float64 }
func (p Point) Distance(q Point) float64 {}``````
• `(p Point)` is called the method's receiver.
• Though methods are placed under its receiver type, `T` and `*T` are considered the same receiver type.
• It should be avoided to use the receiver type `T` for some methods and `*T` for others. All `T` or `All ~*T`.
• Generally, receivers will be referred frequently, giving a short name is recommended, like the first letter of the type name.
• Each type has its own name space for methods, so it is possible to use the same method name for different types.
• Unlike other languages, in Go, it is allowed to define methods for any types, even primitive types.
It is possible to call methods of embedded types
``````type Point struct{ X, Y float64 }

type Circle struct {
Point
Radius float64
}

func (p Point) Distance(q Point) float64 {}

p := Point{0, 0}
c := Cricle{Point{1, 2}, 3}
c.Distance(p)

// error! only receivers can be promoted
p.Distnace(c)
// To fix it, select the anonymous field explicitly
p.Distnace(c.Point)``````

When the compiler encounters `c.Distance(p)`

1. First try to find `func (Cricle) Distance(Point)`
2. If it does not exist, it looks for the method within the embedded fields
3. If it finds one, it will generate additional wrapper so that it could be called seamlessly.
Method Values and Expressions
``````package main

type Point struct{ X, Y float64 }

func (p Point) Distance(q Point) float64 {
return 0.0
}

p := Point{1, 2}
q := Point{3, 4}

// Method value, bound to `p`
distanceFromP := p.Distance
distanceFromP(q)

// Method expression. The receiver should be passed as the first parameter.
distance := Point.Distance
distance(p, q)``````

# Does Go support function overloading?(functions with the same name) discussion

• No, you cannot define same name methods for different argument types.
• Instead, use the same named methods of different receivers, which is supported.

# Defining Anonymous functions within a loop discussion

Be careful when defining anonymous functions, which use the iterator variable, within a loop. Consider a situation in which you need to define functions which reference elements of a slice.

``````names := []string{"cwkim", "sublee", "suminb", "yeonghoey"}

funcs := []func(){}
for _, name := range names {
funcs = append(funcs, func() {
fmt.Println(name) // wrong! `name` changes over the for loop
})
}

for _, f := range funcs {
f()
}``````
``````yeonghoey
yeonghoey
yeonghoey
yeonghoey
``````

To fix this, we need to define a new scope variable and make the function reference it.

``````names := []string{"cwkim", "sublee", "suminb", "yeonghoey"}

funcs := []func(){}
for _, name := range names {
name := name // necessary!
funcs = append(funcs, func() {
fmt.Println(name)
})
}

for _, f := range funcs {
f()
}``````
``````sublee
cwkim
suminb
yeonghoey
``````