在 Go 中,函数允许你将一组可以从应用程序的其他部分调用的语句组合在一起。
我们一直在调用 fmt.Println() 函数,并且在 main() 函数中编写代码。

函数的定义

在golang中,创建函数的语法为:

func functionname(parametername type) returntype {
 //function body
}

最简单的示例如下:

func add(a int, b int) int {
	return a + b
}

func main() {
	fmt.Println(add(1, 2))  //3
}

如果多个参数的类型相同,也可以只写一次。如:

func add(a, b int) int {
	return a + b
}

main函数

main函数是Go 中的所有可执行程序都具有此函数,因为它是程序的起点。
你的程序中只能有一个 main() 函数。

当然,如果创建的是 Go 包,则无需编写 main() 函数。

main() 函数没有任何参数,并且不返回任何内容。 但这并不意味着其不能从用户读取值,如命令行参数。
如要访问 Go 中的命令行参数,可以使用用于保存传递到程序的所有参数的 os 包 和 os.Args 变量来执行操作。

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    number1, _ := strconv.Atoi(os.Args[1])
    number2, _ := strconv.Atoi(os.Args[2])
    fmt.Println("Sum:", number1+number2)
}

os.Args 变量包含传递给程序的每个命令行参数。 由于这些值的类型为 string,因此需要将它们转换为 int 以进行求和。

要执行上述代码,并携带命令行参数,可以如下使用:

go run main.go 3 5
// 输出:Sum:8

返回多个值

在 Go 中,函数可以返回多个值。 你可以采用类似于定义函数参数的方式来定义这些值。 换句话说,你可以指定一个类型和名称,但该名称是可选的。

例如,假设你想要创建一个函数,以将两个数字求和,又让它们相乘。 函数代码将如下所示:

func calc(number1, number2 int) (int, int) {
	sum := number1 + number2
	mul := number1 * number2
	return sum, mul
}

func main() {
	sum, mul := calc(3, 5)
	fmt.Printf("和为 %d,乘积为 %d", sum, mul)
}
//输出:和为 8,乘积为 15

Named return values

在 Go 中,你还可以为函数的返回值设置名称,将其当作一个局部变量。
例如上述函数的等价代码如下:

func calc(number1, number2 int) (sum int, mul int) {
	sum = number1 + number2
	mul = number1 * number2
	return
}

func main() {
	sum, mul := calc(3, 5)
	fmt.Printf("和为 %d,乘积为 %d", sum, mul)
}

你还可以在函数中使用该变量,并且只需在末尾添加 return 行。 Go 将返回这些返回变量的当前值。

Blank Identifier

Go 的另一个有趣功能是,如果不需要函数的某个返回值,可以通过将返回值分配给 Blank Identifier _ 变量来放弃该返回值。 _ 变量是 Go 忽略返回值的惯用方式。 它允许程序进行编译。 因此,如果只需要求和,则可以使用以下代码:

sum, _ := calc1(3, 5)
fmt.Printf("和为 %d", sum)

更改函数参数值(指针)

Go 是“按值传递”编程语言。 每次向函数传递值时,Go 都会使用该值并创建本地副本(内存中的新变量)。
因此将值传递给函数时,该函数中的每个更改都不会影响调用方。

例如,假设你创建了一个用于更新人员姓名的函数:

func updateName(name string) {
	name = "David"
}

func main() {
	firstName := "John"
	updateName(firstName)
	fmt.Println(firstName) // John
}

即使你在函数中将该名称更改为 David,输出仍为 John。由于 updateName 函数中的更改仅会修改本地副本,因此输出不会发生变化。 Go 传递变量的值,而不是变量本身。

如果你希望在 updateName 函数中进行的更改会影响 main 函数中的 firstName 变量,则需要使用指针。
指针是包含另一个变量的内存地址的变量。

向函数发送指针时,不是传递值,而是传递内存地址。
因此,对该变量所做的每个更改都会影响调用方。

func updateNameByPointer(name *string) {
	*name = "David"
}
func main() {
	firstName := "John"
	updateNameByPointer(&firstName)
	fmt.Println(firstName)
}

输出现在显示的是 David,而不是 John.

具体可以参见指针章节。