Golang (also known as Go) is a compiled programming language designed to increase developer productivity by writing code simply and quickly. Among them, functions are one of the very important components in Golang, and they provide the reusability and organization of the code. In this article, we will dig into several aspects of the Golang function.
1. Declaration of function
In Golang, the declaration of a function consists of a function name, a parameter list, and a return value. Here is a simple example:
func add(x int, y int) int { return x + y }
In the example above, we define a function called add which has two arguments x and y, with a return type int. Inside the function body, we add two parameters and return their sum.
The parameters and return value types of functions in Golang can be omitted, and the compiler can automatically deduce the types. For example, the above example can be simplified to:
func add(x, y int) int { return x + y }
2. Function parameters
In Golang, the parameters of a function can be of any type, including basic types (such as int, float, string, etc.), structures, arrays, slices, interfaces, etc. Here is an example of a function that accepts parameters of a structure type:
type Person struct { Name string Age int } func printPerson(p Person) { ("Name: %s, Age: %d\n", , ) }
In the example above, we define a structure type named Person and accept a Person type parameter in the printPerson function. In the function body, we use the function to print out the name and age of Person.
The parameters of a function in Golang can be value type or pointer type. If we pass a value type parameter, a copy of the parameter will be copied inside the function. If we pass a pointer type parameter, the parameter can be modified inside the function. For example:
func modifyPerson(p *Person) { = 30 } func main() { p := Person{"Tom", 20} ("Before:", p) modifyPerson(&p) ("After:", p) }
In the example above, we define a function called modifyPerson that accepts a pointer to the Person type. Within the function body, we modified Person's age to 30. In the main function, we create a variable p of type Person and pass a pointer to p when calling the modifyPerson function. After the function returns, the age of p has been modified to 30.
3. Return value of function
In Golang, a function can return multiple values. Here is an example of a function that returns two values:
func swap(x, y int) (int, int) { return y, x }
In the example above, we define a function called swap which takes two integer types parameters x and y and returns the result after the values of these two parameters are exchanged.
The return value of a function in Golang can be named or anonymous. If the return value is named, it can be used directly in the function body. If the return value is anonymous, you need to use the return statement to return the value. Here is an example of a function that named the return value:
func divide(x, y float64) (result float64, err error) { if y == 0 { err = ("divide by zero") return } result = x / y return }
In the example above, we define a function called divide that takes two parameters x and y of type float64 and returns a result of type float64 and an error of type error. In the function body, if y is equal to 0, an error of divide by zero will be returned, otherwise the result of x/y will be returned.
Functions in Golang can have multiple return values. For example, the following is an example of a function that returns three values:
func calculate(x, y int) (int, int, int) { return x + y, x - y, x * y }
In the example above, we define a function called calculate which takes parameters x and y of two integer types and returns the sum, difference and product of these two parameters.
4. Variable scope of function
In Golang, variables inside a function are only visible inside the function and cannot be accessed by external code. Here is an example:
func printNum() { num := 10 (num) } func main() { printNum() (num) // Error: undefined: num }
In the example above, we define a function called printNum, define a variable num inside the function, and print out the value of the variable using the function. In the main function, we call the printNum function and try to access the variable num, but it will cause a compilation error.
If a variable with the same name as the external variable is defined inside the function, the variables inside the function will mask the external variable, for example:
var num int = 20 func printNum() { num := 10 (num) } func main() { printNum() (num) // Output: 20 }
In the example above, we define a global variable named num and assign a value of 20. Inside the printNum function, we define a local variable named num and assign a value of 10. After calling the printNum function, we print the value of the global variable num again, and the result is 20.
5. Function closure
In Golang, a function can be a closure that can access variables of its external functions. Here is a simple example:
func add(x int) func(int) int { return func(y int) int { return x + y } } func main() { f := add(10) (f(5)) // Output: 15 }
In the example above, we define a function called add that takes an integer type parameter x and returns a function that takes an integer type parameter y and returns the sum of two parameters. In the main function, we call the add function, pass the parameter 10, and assign the returned function to the variable f. Then, we call the variable f, pass parameter 5, and print out the result 15.
In the above example, the add function returns an anonymous function, which forms a closure that can access the parameter x of the add function. In the main function, we call the add function and assign the returned function to the variable f. At this time, the f variable contains the value of the parameter x, that is, 10. Then, we call the variable f and pass the parameter 5. At this time, the x value in the closure function is 10, the y value is 5, and the closure function returns 10+5=15.
In Golang, access to external variables by closure functions is achieved through value copying, rather than by reference. This means that if the closure function is called before the external variable changes, it will still access the old value of the external variable. Here is an example:
func main() { x := 1 f := func() { (x) } x = 2 f() // Output: 1 }
In the example above, we define a variable x with the value assigned to 1. We then define a closure function f that prints the value of the variable x. Next, we change the value of the variable x to 2 and call the closure function f. At this time, the closure function prints the old value of the variable x to 1.
6. Function method
In Golang, functions can be defined on a structure, called a method of a structure. Compared with general functions, this method has an additional receiver parameter to represent the structure instance that calls the method. Here is a simple example:
type Rectangle struct { width, height float64 } func (r Rectangle) Area() float64 { return * } func main() { r := Rectangle{3, 4} (()) // Output: 12 }
In the example above, we define a structure called Rectangle that has two fields of type float64 width and height. We then define a method called Area, whose receiver is a variable of type Rectangle, returning an area of type float64. In the main function, we create a variable r of type Rectangle and call its Area method to output the area of the rectangle.
In the example above, the receiver type of the Area method is Rectangle, which is enclosed in brackets before the method name. The receiver type is specified before the method name, and it can be a structure, pointer type, or interface type. If the receiver type is a structure or pointer type, it can modify the receiver's field in the method. If the receiver type is an interface type, the receiver cannot be modified in the method.
Here is an example of the receiver type pointer type:
type Rectangle struct { width, height float64 } func (r *Rectangle) Scale(s float64) { *= s *= s } func main() { r := &Rectangle{3, 4} (2) (, ) // Output: 6 8 }
In the example above, we define a method called Scale whose receiver is a pointer of type Rectangle. In the Scale method, we modify the receiver's field through pointers. In the main function, we create a pointer r of type Rectangle and call its Scale method, multiplying its length and width by 2. Then we print out the length and width of r and output 6 8.
Methods where the receiver type is pointer type can be used to modify the receiver's field. If the method's receiver is a value type, it cannot modify the receiver's field. If the receiver of the method is of a pointer type, it can modify the field of the receiver. In practical applications, we usually choose to use value type or pointer type as the receiver of the method as needed.
7. Anonymous functions and closures
In Golang, functions can be defined as anonymous functions. Anonymous functions can be defined inside the function or used as a parameter or return value of the function. Here is an example of an anonymous function as a function parameter:
func Filter(numbers []int, f func(int) bool) []int { var result []int for _, v := range numbers { if f(v) { result = append(result, v) } } return result } func main() { numbers := []int{1, 2, 3, 4, 5, 6} evens := Filter(numbers, func(n int) bool { return n%2 == 0 }) (evens) // Output: [2 4 6] }
In the example above, we define a function called Filter that accepts a slice of integer type numbers and a function f that returns a Boolean type. The Filter function adds elements that meet the conditions to a new slice result by traversing the numbers slice, and returns result. In the main function, we create a slice number of integer type, call the Filter function, and pass an anonymous function to it as a second parameter. Anonymous function checks whether the given integer is an even number and returns the result as a Boolean value. The Filter function passes an anonymous function as an argument to it and filters elements in the numbers slice based on the results of the anonymous function. Finally, the Filter function returns a slice of the element that satisfies the condition.
Another useful concept is closure. A closure is a whole formed by a function with its referenced external variables that can access the variables it references. Here is an example of using closures:
func Counter() func() int { i := 0 return func() int { i++ return i } } func main() { c1 := Counter() (c1()) // Output: 1 (c1()) // Output: 2 c2 := Counter() (c2()) // Output: 1 }
In the example above, we define a function called Counter which returns a function. Inside the Counter function, we define an integer variable i and return an anonymous function. Anonymous function will add the value of i to 1 and return the result. In the main function, we call the Counter function twice and assign the returned function to different variables. We call c1 twice, and each call c1 returns an incremental integer value. We call c2 once and it returns 1 because it is a new closure.
In Golang, the function is a first-class citizen. This means that functions can be passed and used like variables. Functions can be passed as parameters to other functions, or as return values for other functions. Anonymous functions and closures are one of the powerful functional features in Golang, which make functions more flexible and composable.
8. Summary
Golang's functions are a powerful and flexible tool that allows us to structure our code, avoid duplication, and improve readability and maintainability. In this article, we discuss the basic syntax and usage of functions in Golang. We also introduce multiple features of functions, including variable-length parameters, multiple return values, methods, anonymous functions, and closures. By deeply learning Golang's functions, we can better understand Golang's programming model and improve code quality and efficiency.
The above is a detailed explanation of Golang's function characteristics in detail. For more information about Golang's function characteristics, please pay attention to my other related articles!