Modular Functions in Programming

GoGoBeginner
Practice Now

Introduction

In the previous programs, we only used one main function. However, as the program becomes more complex, we can split it into several modular functions. By abstracting the operations with the same functionality into a function, we can simply call the function when needed. It also improves collaboration among multiple people and enhances code readability.

Now, let's step into the world of functions together.

Knowledge Points:

  • What is a function
  • Function declaration
  • Pass by value
  • Pass by reference
  • Multiple return values
  • Variadic parameters

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("`Go`")) -.-> go/FunctionsandControlFlowGroup(["`Functions and Control Flow`"]) go(("`Go`")) -.-> go/DataTypesandStructuresGroup(["`Data Types and Structures`"]) go/FunctionsandControlFlowGroup -.-> go/for("`For`") go/FunctionsandControlFlowGroup -.-> go/if_else("`If Else`") go/FunctionsandControlFlowGroup -.-> go/range("`Range`") go/FunctionsandControlFlowGroup -.-> go/functions("`Functions`") go/FunctionsandControlFlowGroup -.-> go/closures("`Closures`") go/DataTypesandStructuresGroup -.-> go/pointers("`Pointers`") subgraph Lab Skills go/for -.-> lab-149098{{"`Modular Functions in Programming`"}} go/if_else -.-> lab-149098{{"`Modular Functions in Programming`"}} go/range -.-> lab-149098{{"`Modular Functions in Programming`"}} go/functions -.-> lab-149098{{"`Modular Functions in Programming`"}} go/closures -.-> lab-149098{{"`Modular Functions in Programming`"}} go/pointers -.-> lab-149098{{"`Modular Functions in Programming`"}} end

Function Introduction

First, let's create a new file named func.go and enter the following code:

package main

import "fmt"

func main() {
    a1, b1 := 12, 4
    a2, b2 := 12, 0
    if b1 == 0 {
        fmt.Println("The divisor cannot be 0")
    } else {
        fmt.Println(a1 / b1)
    }

    if b2 == 0 {
        fmt.Println("The divisor cannot be 0")
    } else {
        fmt.Println(a2 / b2)
    }
}

In this program, we calculate the results of dividing two sets of numbers. Every time we calculate, we check the divisor.

If we want to calculate more sets of data, it will be redundant to write a separate conditional statement for each set. In this case, we can write the repetitive code into a function and call it directly when needed.

Function Declaration

In the previous experiments, regardless of whether the program was simple or complex, we only used the main function for operations.

A program can only have one main function, which is the entry point of the program. When we run the program, other functions are called and executed directly or indirectly within the main function.

Now let's take a look at the syntax of functions:

func functionName(parameters...)(returnValues...){
    code block
}

Here, the function name is used to identify the function. The following rules apply to the function name:

  • It can consist of letters, numbers, and underscores. However, the first letter of the function name cannot be a number. For example, func 3ab(){} is not valid.
  • When the first letter is uppercase, it can be referenced by code in external packages. When the first letter is lowercase, it can only be used within the package. This is similar to public and private functions.

The parameter list declares the number and type of parameters passed into the function:

  • The parameter list can be empty or contain multiple parameters.

  • Each parameter consists of a parameter name and a parameter type. For example, in the parameter list below, we declare two variables of the int type.

    func test(a int, b int) (res int){}

The return value list is used to return the values needed after the function is executed:

  • The return value list is similar to the parameter list. The number of parameters can be any value.

  • Generally, the return list consists of variable names and variable types, and the variable name is optional.

  • If only one variable is returned and only the variable type is declared, the parentheses can be omitted. For example:

    func test(a int, b string) int{}

When the parameter types are the same, we can use the short writing mode. The two functions below have the same functionality:

func test(a int, b int, c string, d string)(res1 int, res2 int, res3 string){}

// Short writing mode
func test(a, b int, c, d string)(res1, res2 int, res3 string){}

Now let's rewrite the program we mentioned earlier:

package main

import "fmt"

func check(a int) bool {
    if a == 0 {
        fmt.Println("The divisor cannot be 0")
        return false
    }
    return true
}
func main() {
    a1, b1 := 12, 4
    a2, b2 := 12, 0
    if check(b1) {
        fmt.Println(a1 / b1)
    }
    if check(b2) {
        fmt.Println(a2 / b2)
    }
}

The result is as follows:

3
The divisor cannot be 0

Here, we extract the code that checks whether the divisor is 0 into a separate function called check. When the divisor is 0, it outputs a corresponding prompt and returns false, otherwise it returns true. We only need to call the check statement when using it.

init Function

We know that the main function is the entry point of the program. However, in this section, we will introduce the init function, which runs before the main function.

We can use the init function for variable initialization, registration, or checking the runtime environment.

Now let's look at an example:

package main

import "fmt"

func init() {
    fmt.Println("init statement")
}

func main() {
    fmt.Println("main statement")
}

The result is as follows:

init statement
main statement

In Go, the init function has the following characteristics:

  • It does not have any input parameters or return values.
  • It cannot be called by other functions.
  • There can be multiple init functions in the same code file or the same package. The execution order is as follows:
    • The init function that appears earlier in the same code file will be executed earlier.
    • Files that have earlier alphabetical order in the same package will be executed earlier. For example, if the same package contains the following files with init functions:
      a1.go
      a2.go
      b1.go
      The execution order will be a1.go, a2.go, b1.go, because a > b and 1 > 2.

Multiple Return Values

Go functions not only support multiple input parameters, but also support returning multiple values.

package main

import "fmt"

// Calculate and return the addition, subtraction, multiplication, and remainder of two parameters
// When the return types are the same, you can also use the short writing mode for the types.
// For example: `func cal(a, b int) (add, sub, mul, rem int)`
func cal(a, b int) (add int, sub int, mul int, rem int) {
    return a + b, a - b, a * b, a % b
}

func main() {
    res1, res2, res3, res4 := cal(90, 12)
    fmt.Println(res1, res2, res3, res4)
}

The result is as follows:

102 78 1080 6

In this program, we use the cal function to calculate the addition, subtraction, multiplication, and remainder of two integers, and return the results.

Variadic Parameters

When using the Println function, we can see that it can output multiple parameters. For example:

fmt.Println("a", "b", "c")

By checking the definition of the function:

// interface{} is an empty interface, which will be learned later
// Here, it can represent any data type
func Println(a ...interface{}) (n int, err error)

We can see that the Println function uses the ... syntax to indicate that the parameter list is variable.

Now let's look at an example, where we iterate through and output the variadic parameters.

package main

import "fmt"

func printX(a ...string) {
    for _, v := range a {
        fmt.Println(v)
    }
}
func main() {
    printX("lan", "qiao", "course")
}

The result is as follows:

lan
qiao
course

Summary

In this lab, we introduced the basic concepts of functions. Now let's summarize the key points:

  • A structure is a composite type that can contain multiple data types.
  • The value of a structure is the initial value of its type when it is not assigned.
  • There are three ways to instantiate a structure.

In the next section, we will learn about anonymous functions in depth.

Other Go Tutorials you may like