如何在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 中,您必须为每个参数指定 数据类型

让我们创建一个将单词重复指定次数的程序。 它需要一个名为 wordstring 参数和一个名为 repsint 参数来重复单词的次数。

重复.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

如果你有一组参数都是相同的值,你可以省略每次指定类型。 让我们创建一个小程序,接收参数 xyz,这些参数都是 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

该函数还打印 abc,根据这个数学,我们期望 a 等于 3 , b4c5。 让我们运行程序:

go run add_numbers.go
Output3 4 5

当我们将 123 作为参数传递给 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 的值,因此将执行此代码分支。 请注意,当我们从函数返回时,我们必须同时提供 stringerror 返回值。 因为提供的参数导致错误,我们将为第一个返回值传回一个空白字符串,并为第二个返回值传回错误。

main() 函数中,我们可以通过声明两个新变量 valueerr 来接收两个返回值。 因为返回中可能有错误,我们想在继续我们的程序之前检查我们是否收到错误。 在这个例子中,我们确实收到了一个错误。 我们从main()函数中打印出错误和return退出程序。

如果没有错误,我们将打印出函数的返回值。

注意: 最好只返回两个或三个值。 此外,您应该始终将所有错误作为函数的最后一个返回值返回。


运行程序将产生以下输出:

Outputinvalid value of -1 provided for reps. value must be greater than 0.

在本节中,我们回顾了如何使用 return 语句从函数返回多个值。

结论

函数是在程序中执行操作的指令代码块,有助于使我们的代码可重用和模块化。

要了解有关如何使代码更加模块化的更多信息,您可以阅读我们关于 如何在 Go 中编写包的指南。