如何在Go中定义和调用函数
介绍
函数 是一段代码,一旦定义,就可以重用。 函数用于通过将代码分解为可在整个程序中多次使用的小型、可理解的任务来使您的代码更易于理解。
Go 附带了一个强大的标准库,其中包含许多预定义的函数。 您可能已经从 fmt 包中熟悉的是:
fmt.Println()
将对象打印到标准输出(很可能是您的终端)。fmt.Printf()
这将允许您格式化打印输出。
函数名称包括括号,并且可能包括参数。
在本教程中,我们将介绍如何定义您自己的函数以在您的编码项目中使用。
定义函数
让我们从翻经典的“Hello, World!”开始吧。 将 编程到一个函数中。
我们将在我们选择的文本编辑器中创建一个新的文本文件,并调用程序 hello.go
。 然后,我们将定义函数。
使用 func
关键字定义函数。 然后是您选择的名称和一组括号,其中包含函数将采用的任何参数(它们可以为空)。 函数代码行用大括号 {}
括起来。
在这种情况下,我们将定义一个名为 hello()
的函数:
你好.go
func hello() {}
这设置了用于创建函数的初始语句。
从这里开始,我们将添加第二行来提供函数功能的说明。 在这种情况下,我们将 Hello, World!
打印到控制台:
你好.go
func hello() { fmt.Println("Hello, World!") }
我们的函数现在已经完全定义好了,但是如果我们此时运行程序,什么都不会发生,因为我们没有调用函数。
因此,在我们的 main()
功能块内部,让我们用 hello()
调用该函数:
你好.go
package main import "fmt" func main() { hello() } func hello() { fmt.Println("Hello, World!") }
现在,让我们运行程序:
go run hello.go
您将收到以下输出:
OutputHello, World!
请注意,我们还引入了一个名为 main()
的函数。 main()
函数是一个特殊函数,它告诉编译器这是程序应该 开始 的地方。 对于任何想要成为 executable 的程序(可以从命令行运行的程序),您将需要一个 main()
函数。 main()
函数必须只出现一次,在 main()
package 中,并且不接收和返回任何参数。 这允许在任何 Go 程序中执行 程序 。 根据以下示例:
main.go
package main import "fmt" func main() { fmt.Println("this is the main section of the program") }
函数可以比我们定义的 hello()
函数更复杂。 我们可以在函数块中使用 for 循环 、 条件语句 等。
例如,以下函数使用条件语句检查 name
变量的输入是否包含元音,然后使用 for
循环遍历 name
中的字母] 细绳。
名字.go
package main import ( "fmt" "strings" ) func main() { names() } func names() { fmt.Println("Enter your name:") var name string fmt.Scanln(&name) // Check whether name has a vowel for _, v := range strings.ToLower(name) { if v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' { fmt.Println("Your name contains a vowel.") return } } fmt.Println("Your name does not contain a vowel.") }
我们在这里定义的 names()
函数设置一个带有输入的 name
变量,然后在 for
循环中设置一个条件语句。 这显示了如何在函数定义中组织代码。 但是,根据我们对程序的意图以及我们希望如何设置代码,我们可能希望将条件语句和 for
循环定义为两个独立的函数。
在程序中定义函数使我们的代码模块化和可重用,这样我们就可以调用相同的函数而无需重写它们。
使用参数
到目前为止,我们已经研究了带有空括号且不带参数的函数,但是我们可以在函数定义中的括号内定义参数。
parameter 是函数定义中的命名实体,指定函数可以接受的参数。 在 Go 中,您必须为每个参数指定 数据类型 。
让我们创建一个将单词重复指定次数的程序。 它需要一个名为 word
的 string
参数和一个名为 reps
的 int
参数来重复单词的次数。
重复.go
package main import "fmt" func main() { repeat("Sammy", 5) } func repeat(word string, reps int) { for i := 0; i < reps; i++ { fmt.Print(word) } }
我们为 word
参数传递了值 Sammy
,为 reps
参数传递了 5
。 这些值按照给定的顺序与每个参数相对应。 repeat
函数有一个 for
循环,它将迭代 reps
参数指定的次数。 对于每次迭代,都会打印 word
参数的值。
这是程序的输出:
OutputSammySammySammySammySammy
如果你有一组参数都是相同的值,你可以省略每次指定类型。 让我们创建一个小程序,接收参数 x
、y
和 z
,这些参数都是 int
值。 我们将创建一个函数,将参数添加到不同的配置中。 这些总和将由函数打印。 然后我们将调用该函数并将数字传递给该函数。
add_numbers.go
package main import "fmt" func main() { addNumbers(1, 2, 3) } func addNumbers(x, y, z int) { a := x + y b := x + z c := y + z fmt.Println(a, b, c) }
当我们为 addNumbers
创建函数签名时,我们不需要每次都指定类型,只需要在最后指定。
我们将数字 1
传递给 x
参数,2
传递给 y
参数, 3
传递给 z
参数。 这些值按照给定的顺序与每个参数对应。
该程序正在根据我们传递给参数的值进行以下数学运算:
a = 1 + 2 b = 1 + 3 c = 2 + 3
该函数还打印 a
、b
和 c
,根据这个数学,我们期望 a
等于 3
, b
为 4
,c
为 5
。 让我们运行程序:
go run add_numbers.go
Output3 4 5
当我们将 1
、2
和 3
作为参数传递给 addNumbers()
函数时,我们会收到预期的输出。
参数是通常在函数定义中定义为变量的参数。 当您运行方法时,可以为它们赋值,将参数传递给函数。
返回值
可以将参数值传递给函数,函数也可以产生值。
函数可以使用 return
语句生成一个值,该语句将退出函数,并且 可选地 将表达式传递回调用者。 还必须指定返回数据类型。
到目前为止,我们在函数中使用了 fmt.Println()
语句而不是 return
语句。 让我们创建一个程序,而不是打印将返回一个变量。
在一个名为 double.go
的新文本文件中,我们将创建一个将参数 x
加倍并返回变量 y
的程序。 我们发出调用以打印 result
变量,该变量是通过运行 double()
函数并传入 3
形成的:
双去
package main import "fmt" func main() { result := double(3) fmt.Println(result) } func double(x int) int { y := x * 2 return y }
我们可以运行程序并查看输出:
go run double.go
Output6
整数 6
作为输出返回,这就是我们将 3
乘以 2
所期望的结果。
如果函数指定了返回值,则必须在代码中提供返回值。 如果不这样做,您将收到编译错误。
我们可以通过用 return 语句注释掉这一行来证明这一点:
双去
package main import "fmt" func main() { result := double(3) fmt.Println(result) } func double(x int) int { y := x * 2 // return y }
现在,让我们再次运行程序:
go run double.go
Output./double.go:13:1: missing return at end of function
此处不使用return
语句,程序无法编译。
函数在遇到 return
语句时立即退出,即使它们不在函数末尾:
return_loop.go
package main import "fmt" func main() { loopFive() } func loopFive() { for i := 0; i < 25; i++ { fmt.Print(i) if i == 5 { // Stop function at i == 5 return } } fmt.Println("This line will not execute.") }
在这里,我们遍历 for
循环,并告诉循环运行 25
迭代。 但是,在 for
循环中,我们有一个条件 if
语句,用于检查 i
的值是否等于 5
。 如果是,我们发出 return
语句。 因为我们在loopFive
函数中,所以函数中任意点的任何return
都会退出函数。 因此,我们永远不会到达该函数的最后一行来打印语句 This line will not execute.
。
在 for
循环中使用 return
语句结束函数,因此循环外的行将不会运行。 相反,如果我们使用了 break 语句,那么此时只有循环会退出,最后的 fmt.Println()
行会运行。
return
语句退出函数,如果在函数签名中指定,则可能返回一个值。
返回多个值
一个函数可以指定多个返回值。 让我们检查 repeat.go
程序并让它返回两个值。 第一个是重复值,如果 reps
参数不是大于 0
的值,则第二个是错误:
重复.go
package main import "fmt" func main() { val, err := repeat("Sammy", -1) if err != nil { fmt.Println(err) return } fmt.Println(val) } func repeat(word string, reps int) (string, error) { if reps <= 0 { return "", fmt.Errorf("invalid value of %d provided for reps. value must be greater than 0.", reps) } var value string for i := 0; i < reps; i++ { value = value + word } return value, nil }
repeat
函数所做的第一件事是检查 reps
参数是否为有效值。 任何不大于 0
的值都会导致错误。 由于我们传入了 -1
的值,因此将执行此代码分支。 请注意,当我们从函数返回时,我们必须同时提供 string
和 error
返回值。 因为提供的参数导致错误,我们将为第一个返回值传回一个空白字符串,并为第二个返回值传回错误。
在 main()
函数中,我们可以通过声明两个新变量 value
和 err
来接收两个返回值。 因为返回中可能有错误,我们想在继续我们的程序之前检查我们是否收到错误。 在这个例子中,我们确实收到了一个错误。 我们从main()
函数中打印出错误和return
退出程序。
如果没有错误,我们将打印出函数的返回值。
注意: 最好只返回两个或三个值。 此外,您应该始终将所有错误作为函数的最后一个返回值返回。
运行程序将产生以下输出:
Outputinvalid value of -1 provided for reps. value must be greater than 0.
在本节中,我们回顾了如何使用 return
语句从函数返回多个值。
结论
函数是在程序中执行操作的指令代码块,有助于使我们的代码可重用和模块化。
要了解有关如何使代码更加模块化的更多信息,您可以阅读我们关于 如何在 Go 中编写包的指南。