跳转到主要内容

介绍


函数是一段代码,一旦定义,就可以重用。函数用于通过将代码分解为可在整个程序中多次使用的小型、可理解的任务来使您的代码更易于理解。

Go 附带了一个强大的标准库,其中包含许多预定义的函数。您可能已经从 fmt 包中熟悉的是:

  • fmt.Println() 会将对象打印到标准输出(很可能是您的终端)。
  • fmt.Printf() 这将允许您格式化打印输出。

函数名称包括括号,并且可能包括参数。

在本教程中,我们将介绍如何定义您自己的函数以在您的编码项目中使用。

定义函数


让我们从经典的“Hello, World!”开始。程序化成一个函数。

我们将在我们选择的文本编辑器中创建一个新的文本文件,并调用程序 hello.go。然后,我们将定义函数。

函数是使用 func 关键字定义的。然后是您选择的名称和一组括号,其中包含函数将采用的任何参数(它们可以为空)。函数代码行用大括号 {} 括起来。

在这种情况下,我们将定义一个名为 hello() 的函数:

hello.go


func hello() {}


这设置了用于创建函数的初始语句。

从这里开始,我们将添加第二行来提供函数功能的说明。在这种情况下,我们将打印 Hello, World!到控制台:

hello.go


func hello() {
    fmt.Println("Hello, World!")
}


我们的函数现在已经完全定义好了,但是如果我们此时运行程序,什么都不会发生,因为我们没有调用该函数。

因此,在我们的 main() 函数块中,让我们用 hello() 调用该函数:

hello.go

package main

import "fmt"

func main() {
    hello()
}

func hello() {
    fmt.Println("Hello, World!")
}

现在,让我们运行程序:

go run hello.go


您将收到以下输出:

Output

Hello, World!


请注意,我们还引入了一个名为 main() 的函数。 main() 函数是一个特殊函数,它告诉编译器程序应该从这里开始。 对于您希望可执行的任何程序(可以从命令行运行的程序),您将需要一个 main() 函数。 main() 函数必须只出现一次,在 main() 包中,并且不接收和返回任何参数。 这允许在任何 Go 程序中执行程序。 根据以下示例:

main.go

package main

import "fmt"

func main() {
    fmt.Println("this is the main section of the program")
}

函数可以比我们定义的 hello() 函数更复杂。 我们可以在函数块中使用 for 循环、条件语句等。

例如,以下函数使用条件语句检查 name 变量的输入是否包含元音,然后使用 for 循环遍历 name 字符串中的字母。

names.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() 函数设置了一个带有输入的名称变量,然后在 for 循环中设置了一个条件语句。这显示了如何在函数定义中组织代码。但是,根据我们对程序的意图以及我们希望如何设置代码,我们可能希望将条件语句和 for 循环定义为两个独立的函数。

在程序中定义函数使我们的代码模块化和可重用,这样我们就可以调用相同的函数而无需重写它们。

使用参数


到目前为止,我们已经研究了带有空括号且不带参数的函数,但是我们可以在函数定义中的括号内定义参数。

参数是函数定义中的命名实体,指定函数可以接受的参数。在 Go 中,您必须为每个参数指定数据类型。

让我们创建一个将单词重复指定次数的程序。它将采用一个名为 word 的字符串参数和一个名为 reps 的 int 参数来表示重复单词的次数。

repeat.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 参数的值。

这是程序的输出:

Output
SammySammySammySammySammy


如果你有一组参数都是相同的值,你可以省略每次指定类型。 让我们创建一个小程序,接收参数 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 创建函数签名时,我们不需要每次都指定类型,而只在最后指定。

我们为 x 参数传递了数字 1,为 y 参数传递了 2 in,为 z 参数传递了 3 in。这些值按照给定的顺序与每个参数对应。

该程序正在根据我们传递给参数的值进行以下数学运算:

  • a = 1 + 2
  • b = 1 + 3
  • c = 2 + 3

该函数还打印 a、b 和 c,根据这个数学,我们期望 a 等于 3,b 等于 4,c 等于 5。让我们运行程序:

go run add_numbers.go

Output
3 4 5


当我们将 1、2 和 3 作为参数传递给 addNumbers() 函数时,我们会收到预期的输出。

参数是通常在函数定义中定义为变量的参数。当您运行方法时,可以为它们赋值,将参数传递给函数。

返回值


可以将参数值传递给函数,函数也可以产生值。

函数可以使用 return 语句生成一个值,该语句将退出函数并可选地将表达式传递回调用者。还必须指定返回数据类型。

到目前为止,我们在函数中使用了 fmt.Println() 语句而不是 return 语句。让我们创建一个程序,而不是打印将返回一个变量。

在一个名为 double.go 的新文本文件中,我们将创建一个将参数 x 加倍并返回变量 y 的程序。我们发出调用以打印结果变量,该变量是通过运行带有 3 的 double() 函数形成的:

double.go

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

6


整数 6 作为输出返回,这是我们将 3 乘以 2 所期望的结果。

如果函数指定了返回值,则必须在代码中提供返回值。 如果不这样做,您将收到编译错误。

我们可以通过用 return 语句注释掉这一行来证明这一点:

double.go

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 函数中,所以函数中任何点的任何返回都将退出该函数。结果,我们永远不会到达这个函数的最后一行来打印语句 这行将不会执行..

在 for 循环中使用 return 语句结束函数,因此循环外的行将不会运行。相反,如果我们使用了 break 语句,那么此时只有循环会退出,并且最后一行 fmt.Println() 会运行。

return 语句退出一个函数,如果在函数签名中指定,它可能会返回一个值。

返回多个值


一个函数可以指定多个返回值。让我们检查 repeat.go 程序并让它返回两个值。第一个将是重复值,如果 reps 参数不是大于 0 的值,则第二个将是错误:

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

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

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

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

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


Output

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


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

结论


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

文章链接