Go Concepts - Functions
External
- Function type specification https://golang.org/ref/spec#Function_types
Internal
Function Definition
A function declaration starts with the func keyword and it consists in a series of statements applied on a number of inputs, resulting in a number of outputs. Same inputs will always result in the same outputs. Function do not depend on a type instance's state. From this perspective, functions are conceptually different from methods.
The parameters and the return types are known as the function's signature.
Syntax
func <name>( [parameter-identifier1] [type1], [parameter-identifier2] [type2], ...) [(<return-type1>, [return-type2], ...)] { // function's body statement1 statement2 ... return <return-value1>, <return-value2> }
func add(a int, b int) int { return a + b; }
The return type declarations are optional, if the function does not return anything.
Multiple Return Values
A function may return one or more results:
func add(a int, b int) (int, int) { return a + b, a - b; }
Also see Communicating Errors.
Return Types can Have Names
func f() (r int) { r = 1 return }
Varidic Functions
Variadic parameters are declared using ellipsis (...).
func f(args ...int) int { // // range can be used to iterate over the individual parameters // for _, arg := range args { // ... } }
Also see:
A slice can be "converted" into its individual components which can be passed as individual arguments to a variadic function, by appending an ellipsis (...) to the slice identifier:
s := []int{1, 2, 3} f(s...)
Functions and Variable Scopes
A function does not have access to variables declares in functions that call it.
A function does have access to package level variables declared in the function's package.
Also see:
Pass by Value vs. Pass by Reference
In Go, all variables are passed by value: when an argument is passed to a function, that argument is copied on the stack.
This is true for built-in types and for user defined types (structs). Because of that, if you want to change a struct inside a function, you should pass a pointer to that struct, not the struct itself.
Even for pointer variables, since the value of the pointer is a memory address, passing pointer variables is still considered pass by value.
Closures
defer
The defer keyword schedules the function it is invoked with to be executed immediately after the function it is invoked from exits, irrespective of how the function exits (even with a panic). The execution is done on the same thread.
defer is used in Go idioms where a resource needs to be closed after it was opened: it keeps the "close" call near the "open" call, so the code is easier to understand. The recommended way to do it is:
f, _ := os.Open(filename) defer f.Close()
Function Literals
The main() Function
Built-in Functions
The built-in functions are available by default, without the need to import any package. They are what the specification calls pre-defined function identifiers. Their semantics depends on the arguments.
- Length and capacity len(), cap()
- close()
- Allocation: new()
- Making slices, maps and channels: make()
- Appending to and copying slices: append(), copy()
- Deletion of map elements delete()
- Handling panics panic(), recover()
- Manipulating complex numbers: complex(), real(), imag()
- Bootstrapping print(), println()
Conversion between Types
Conversions between types look like function invocations, see Conversion between Types.
Methods
A method defines the behavior of a type, and it relies on the state of an instance of the type. The method will - and it is supposed to - change the state. From this point of view, the method is conceptually different from a function.
Lexically, methods are declared independently from the type they are related to: they can declared in a different section of the file from where the type is declared, or in a different file altogether, as long as that file belongs to the same package.
A method is always exported by the package it is enclosed in.
Syntax
A method declaration is similar to a function's, except that in between the func keyword and the name of function we add a receiver. The receiver syntax is similar to a function's parameters: (name type):
func (<receiver>) <method-name> (...) { // the rest of declaration is similar to a function's ... }
Example:
func (bagPtr *Bag) changeBagsColor(color string) { ... }
Once a method was associated to the type, the type's instances allow invocation of the method using the . operator.