CodeGo

Learn The Go Programming Language — Functions


Up until now, we only called Go-defined functions. We will now create our own functions.

Declaring Functions

A simple function declaration might look like this

func myFunc() {
fmt.Println("My Function")
}

A declaration begins with the func keyword, followed by the function’s name, parentheses (), and the code for the function.

Once a function has been declared, you can call it anywhere in your package by typing its name, followed by a pair of parentheses. This will run the code in the function’s block.

In calling myFunc, we do not type the package name and a dot before the function name. A function defined in the current package shouldn’t require the package name when called.

Function names follow the same rules as variable names:

  • The name must begin with a letter, followed by any number of letters or numbers.
  • The names of functions that begin with a capital letter are exported and can be used outside the current package. The name of a function should be lowercase if it is only used within the current package.
  • CamelCase should be used for names with multiple words.

Declaring Function Parameters

If you want calls to your function to include arguments, you will need to declare one or more parameters. 

A parameter is a variable, local to a function, whose value is set when the function is called.

Comma-separated parameters can be declared between parentheses in a function declaration.

When calling a function with parameters, you will need to pass a matching set of arguments. Each parameter in the function will be set to a copy of its corresponding argument value. In the function block, these parameter values are used with the code.

Functions and Variable Scope

Variables declared within function blocks are only valid within that function block, similar to conditional and loop blocks. Variables declared outside a function block will, however, also be in scope within that block, just as they are in conditional and loop blocks. As a result, we can declare a variable at the package level, and access it within any function within that package.

Function Return Values

A function returns values of a specific type. After the parameters in a function declaration, add the type of the return value. In the function block, use the return keyword followed by the value you want to return.

func myFunc(number int) float64 {
return math.Sqrt(float64(number))
}

When a return statement runs, the function exits immediately, without running any code that follows it. 

Declaring Multiple Return Values

To declare multiple return values for a function, place the return value types in the second set of parentheses in the function declaration after the parentheses for the function parameters, separated with commas.

We saw in the previous post that the function also returns an error value along with its main return value. A function can only return an error value if it has an error value to return.

An error value is any value with a method name Error that returns a string. You can create one by passing a string to the errors package’s New function, which will return a new error value. The Error method will return a new error value if you call it on that error value. Calling Error on that error value returns the string you passed to errors.New.

func myFunc(number int) (float64, error) {
if number < 0 {
err := errors.New("Number is negative")
return 0, err
}
  return math.Sqrt(float64(number)), nil
}

If you pass the error value to a function in the fmt package, you don’t need to call its Error method. This function checks whether the values passed to it have Error methods and prints the return value of Error if they do.

You can name the return values if it makes sense for the purpose, similar to parameter names. Named return values to serve as documentation for programmers.

func myFunc(number int) (result float64, errorMsg error) {
if number < 0 {
err := errors.New("Number is negative")
return 0, err
}
return math.Sqrt(float64(number)), nil
}

Always Handle Errors

A function that returns an error value must also return a primary return value. However, any other return values that accompany an error value should be ignored.

Before proceeding with a function that returns an error value, you should test whether it is nil. Any value other than nil indicates an error. At that point, you can decide what to do with the error.

Pass-By-Value Function Parameters

In order to call a function with parameters, you must provide arguments. The value in each argument is copied to the corresponding parameter variable.

Go is a pass-by-value language, function parameters receives a copy of the arguments from the function call.

Passing a variable’s value to a function and having it change it in some way won’t work. Only the copy of the parameter’s value can be changed, not the original. Therefore, any changes you make within the function will not be visible outside of it.

In the main function, after calling updateIndex(), the variable index remains 1.

There is a need for a way to allow a function to alter the original value a variable holds, rather than a copy.

Pointers

You can get the address of a variable using &, which is Go’s “address of” operator.

value := 10
fmt.Println("value is", value)
fmt.Println("Address of value is", &value)

Output

value is 10
Address of value is 0xc000016098

Values that represent the address of a variable are known as pointers because they point to the location where the variable can be found.

The type of a pointer is written with a * symbol, followed by the type of variable the pointer points to. We can declare variables that hold pointers. A pointer variable can only hold pointers to one type of value.

var intPointer *int
var floatPointer *float64
myInt := 10
intPointer = &myInt
myFloat:= 2.14
floatPointer = &myFloat

Accessing/Modifying Value At A Pointer

You can get the value of the variable a pointer refers to by typing the * operator right before the pointer in your code. 

myInt := 10
var intPointer *int = &myInt
fmt.Println("Value at pointer", *intPointer)

Output

Value at pointer 10

The * operator can also be used to update the value at a pointer.

myInt := 10
var intPointer *int = &myInt
*intPointer = 20
fmt.Println("Value at pointer", *intPointer)
fmt.Println("Value", myInt)

Output

Value at pointer 20
Value 20

Using Pointers With Functions

It’s possible to return pointers from functions; just declare that the function’s return type is a pointer type.

func main() {
ptr := getPtr()
fmt.Println("Value at pointer", *ptr)
}
func getPtr() *int {
value := 20
return &value
}

You can also pass pointers to functions as arguments.

func main() {
value := 20
passPtr(&value)
}
func passPtr(ptr *int) {
fmt.Println("Value at Pointer", *ptr)
}

Summary

  • You must declare one or more parameters in the declaration of your function if you want it to accept arguments.
  • You must declare the return value types in the function declaration if you want your function to return one or more values.
  • Variables declared within a function cannot be accessed outside of that function. But you can access a variable declared outside a function (usually at the package level) within that function.
  • There is usually an error in the last value of a function when it returns multiple values. Error values have a method that returns an Error() string that describes the error.
  • You can access the value a pointer holds by putting a right before * it.
  • If a function receives a pointer as a parameter, and it updates the value at that pointer, then the updated value will still be visible outside the function.

References:

https://go.dev/doc

Leave a Reply

Your email address will not be published.