Contents
Outline
In this blog post, I will introduce the details about Function
more deeply and the various ways to use Function in Golang. You can see the full source code of this blog post on the link below.
Function basic
If you want to know the basic of the function in Golang, see the previous blog post.
Variable argument list function
In Golan,g you can use the variable argument list function like the below.
fmt.Println()
fmt.Println(1)
fmt.Println(1, 2, 3, 4, 5)
You can make the variable argument list function with the ...
keyword in Golang.
func FUNCTION_NAME(param ...TYPE) TYPE {
// Code block
}
To check this, create the main.go
file and modify it like the below.
package main
import "fmt"
func sum(nums ...int) int {
fmt.Printf("nums type: %T\n", nums)
sum := 0
for _, num := range nums {
sum += num
}
return sum
}
func main() {
fmt.Println(sum(1, 2, 3, 4, 5))
fmt.Println(sum(10, 20))
fmt.Println(sum())
}
When you run the above code, you can see the following result.
# go run main.go
nums type: []int
15
nums type: []int
30
nums type: []int
0
defer
Golang provides the defer
keyword that is the delay execution statement. The defer
ensures that the statement is executed before the end of the function.
defer STATEMENT
To check this, modify the main.go
file like the below.
package main
import "fmt"
func print() {
defer fmt.Println("World!")
fmt.Println("Hello")
}
func main() {
print()
}
When the code is executed, you can seeh the following result.
# go run main.go
Hello
World!
The defer
is mainly used for returning the OS resource like closing the file that was opend to use it. To check this, modify the main.go
file like the below.
package main
import "os"
func readFile() {
f, err := os.Open("file.txt")
if err != nil {
return
}
f.Close()
}
func readFileDefer() {
f, err := os.Open("file.txt")
defer f.Close()
if err != nil {
return
}
}
func main() {
readFile()
readFileDefer()
}
If the defer
is not used here and the the error occurs before calling the Close
function, the Close
function will not be called.
func readFile() {
f, err := os.Open("file.txt")
if err != nil {
return
}
f.Close()
}
However, if the defer
is used here, the Close
function will be called.
func readFileDefer() {
f, err := os.Open("file.txt")
defer f.Close()
if err != nil {
return
}
}
Function type variable
In Golang, the function can be also used as the type. In here, Function type variable means the variables have the function as value. The function also has the memory address, so we can assign it to the variable.
You can define the function type by Function signature
like the below.
// Function
func add(a, b int) int {
return a + b
}
// Signature
func (int int) int
To check this, modify the main.go
file like the below.
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func multiple(a, b int) int {
return a * b
}
func getOperator(op string) func(int, int) int {
if op == "+" {
return add
} else if op == "*" {
return multiple
} else {
return nil
}
}
func main() {
var op func(int, int) int
op = getOperator("+")
result := op(10, 20)
fmt.Println(result)
op = getOperator("*")
result = op(10, 20)
fmt.Println(result)
}
When the code is executed, you can see the following result.
# go run main.go
30
200
Function signature alias type
You can use the function type more simpley with the alias type and the function signature.
// Function signature alias type
type OperateFunc func(int, int) int
func getOperator(op string) OperateFunc {
}
To check this, modify the main.go
file like the below.
package main
import "fmt"
type OperateFunc func(int, int) int
func add(a, b int) int {
return a + b
}
func multiple(a, b int) int {
return a * b
}
func getOperator(op string) OperateFunc {
if op == "+" {
return add
} else if op == "*" {
return multiple
} else {
return nil
}
}
func main() {
var op OperateFunc
op = getOperator("+")
result := op(10, 20)
fmt.Println(result)
op = getOperator("*")
result = op(10, 20)
fmt.Println(result)
}
When you execute the code, you can see the following result.
# go run main.go
30
200
The alias type makes it easier to use the function signature.
Function literal
In Golang, we can use the function literal(anonymous function).
f := func(a, b int) int {
}
To check this, modify the main.go
file like the below.
package main
import "fmt"
type OperateFunc func(int, int) int
func getOperator(op string) OperateFunc {
if op == "+" {
return func(a, b int) int {
return a + b
}
} else if op == "*" {
return func(a, b int) int {
return a * b
}
} else {
return nil
}
}
func main() {
var op OperateFunc
op = getOperator("+")
result := op(10, 20)
fmt.Println(result)
op = getOperator("*")
result = op(10, 20)
fmt.Println(result)
}
When the code is executed, you can see the following result.
# go run main.go
30
200
In Golang, the function can’t have the state normally, but the function literal can have the state. To check this, modify the main.go
file like the below.
package main
import "fmt"
func main() {
i := 0
f := func() {
i += 10
}
i++
f()
fmt.Println(i)
}
When you execute the code, you can see the following result.
# go run main.go
11
Normal function can’t access the variables defined outside of the function. However, the function literal can access(capture) and use the variables defined outside of the function. The captured value is not copied value, but as a reference copy. In other words, it can be said that the pointer is copied.
To check this, modify the main.go
file like the below.
package main
import "fmt"
func CaptureLoop1() {
f := make([]func(), 3)
fmt.Println("CaptureLoop1")
for i := 0; i < 3; i++ {
f[i] = func() {
fmt.Println(i)
}
}
for i := 0; i < 3; i++ {
f[i]()
}
}
func CaptureLoop2() {
f := make([]func(), 3)
fmt.Println("CaptureLoop2")
for i := 0; i < 3; i++ {
v := i
f[i] = func() {
fmt.Println(v)
}
}
for i := 0; i < 3; i++ {
f[i]()
}
}
func main() {
CaptureLoop1()
CaptureLoop2()
}
When the code is executed, you can see the following result.
# go run main.go
CaptureLoop1
3
3
3
CaptureLoop2
0
1
2
The CaptureLoop1
refers to the i
variable of the for
directly, so 2 that is the last of i
is printed. The CaptureLoop2
refers to the v
variable that is copied from i
and the v
is newly created every time in the for loop, so you can see 0~2 are printed.
Dependency Injection
In Golang, you can use the function type for dependency injection(DI). Dependency injection is a technique that allows you to inject the business logic from the outside instead of defining it inside.
package main
import "fmt"
type PrintConsole func(string)
func PrintHello(p PrintConsole) {
p("Hello, World!")
}
func main() {
PrintHello(func(msg string) {
fmt.Println(msg)
})
}
WHen the code is executed, you can see the following result.
# go run main.go
Hello, World!
PrintHello
doesn’t know what the role of PrintConsole
is(what the business logic has). So, we can say PrintHello
is injected dependency via PrintConsole
.
Completed
Done! we’ve seen the function deeply, and how to use it. Next, try to use the techniques that I introduced to make awsome codes.
Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!
App promotion
Deku
.Deku
created the applications with Flutter.If you have interested, please try to download them for free.