Go Concepts - Functions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

External

Internal

Function Definition

A function declaration starts with the func keyword, followed by the function name and its signature: input parameters and the results, followed by a series of statements in a block. If the function does not return anything, the result declaration can be missing.

The statements are 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.

Function Signature

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;
}

It is idiomatic for Go to return an error value among the return values, see:

Communicating Errors

Return Types can Have Names

func f() (r int) {
   r = 1
   return
}

Varidic Functions

Variadic parameters are declared using ellipsis (...). A function can only have one variadic parameter.

func f(args ...<type>) <return-type> {

    //
    // range can be used to iterate over the individual parameters
    //
   for _, arg := range args {
        // ...
   }
}

Also see:

range

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...)

Function Literals

There are cases when a function definition is needed in-line - to be passed as argument to another function, for example. In this case we use a function literal, which consists in the func keyword, followed by a signature, and the body. No name is required. Example:

func (i int, j int) int {
    return i + j
}

Also see:

Closures
Function Types

Anonymous Functions

An anonymous function is a function that is declared without a name. Anonymous functions are useful in implementing closures.

Anonymous function invocation example:


a := 10

func (i int) {
    fmt.Println(i)
}(a)

<pre>

=Functions and Variable Scopes=

A function does not have access to variables declares in functions that call it.

A function does have access to [[Go_Concepts_-_Lexical_Structure#Package-Level_Variable|package level variables]] declared in the function's package.

Also see:
<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;">
:[[Go_Concepts_-_Lexical_Structure#Variable_Scopes|Variable Scopes]]
</blockquote>

=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 [[Go_Concepts_-_Lexical_Structure#Pointers|pointer variables]], since the value of the pointer is a memory address, passing pointer variables is still considered pass by value.

=Closures=

<blockquote style="background-color: #f9f9f9; border: solid thin lightgrey;">
:[[Go_Closures#Overview|Closures]]
</blockquote>

=<tt>defer</tt>=


The <tt>defer</tt> 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.

<tt>defer</tt> 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:

<pre>
f, _ := os.Open(filename)
defer f.Close()

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.

Special Functions

The init() Function

The init() function contains code executed on package initialization. All init() functions in any code file that is part of the program will be called before the main() function.

A way to trigger package initialization code to execute, even if none of the package identifiers is used in the source code, is to use the blank identifier.

The main() Function

A main() function that takes no arguments and returns no value is the entry point in a Go program. Once the main() function exists, the program exits, regardless of whether there are other in-flight goroutines. More about the main() function, the main package and Go executables can be found here: compiling an executable.

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 struct 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.

Receivers

Value Receivers

Pointer Receivers

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) changeColor(color string) {
    ...
}

Method Invocation

Once a method was associated to the type, the type's instances or pointers to the type's instances allow invocation of the method using the . operator. The . operator work with both the instance and the pointer. For the method declaration above, both invocations that follow are valid:

var b Bag
bPtr := &b

b.changeColor("red")
bPtr.changeColor("blue")

Difference between Functions and Methods