Skip to content

探索Go语言中的函数:构建可重用代码的基石

Go语言以其精炼的语法和强大的功能,为开发者提供了构建高效、可维护代码的坚实基础。Go语言中的函数不仅是执行特定任务的代码块,更是实现代码复用和模块化设计的核心构件。通过精心设计的函数,Go语言极大地简化了代码的复用、组织和测试过程。

函数是任何编程语言中不可或缺的重要组成部分。从本质上讲,函数是对一段逻辑的封装,它将特定的功能抽象并命名,使得在需要时可以通过简单的调用实现功能的复现。这种封装不仅使代码更加清晰和简洁,而且提高了代码的可读性和可维护性。

定义

下面的代码段介绍了Go语言中函数定义的各种情况,以及延迟函数的使用。

go
package main import "fmt" // 函数的定义 func f1(x int, y int) (ret int) {    return x + y } // 无返回值的函数 func f2(x int, y int) {    fmt.Println(x + y) } // 没有参数也没有返回值的 func f3() {    fmt.Println("1111") } // 没有参数 有返回值的 func f4() int {    return 4 } // 返回值可以命名也可以不命名 // 命名的返回值就相当于在函数中声明一个变量 func f5(x int, y int) (ret int) {    ret = x + y  //注意:因为已经在返回值中声明了ret,所以这里用= 而不是:= ,避免重复声明问题    return //因为已经在函数体中声明了ret,所以在return的时候不需要重复声明 } // 多个返回值 func f6() (int, int) {    return 1, 2 } // 多个参数简写的方式 // 当参数的类型一致时,可以将连续的相同参数 前面参数的类型省略 比如: func f7(x, y, z int, a, b string, c, d bool) int {    return x + y + z } // 可变长参数 // 可变长参数必须放在函数参数的最后 func f8(x string, y ...int) {    fmt.Println(x)    fmt.Println(y) } // defer 延迟执行 func deferDemo() {    defer fmt.Println("111") //最先defer的语句最后执行    defer fmt.Println("222")    fmt.Println("333") } // go语言中函数没有默认参数的概念 func main() {    r := f5(1, 2)    fmt.Println(r)    m, n := f6()    fmt.Println(m, n)    r7 := f7(1, 2, 3, "1", "1", true, false)    fmt.Println(r7)    f8("hah") //可变长度 不填也可以    f8("hah", 1, 2, 3, 4)        //延迟函数测试    deferDemo() }

函数可以作为函数的参数

函数不仅仅是执行操作的代码块,它们还是一等公民,意味着函数可以像任何其他变量一样被传递和操作。这种特性极大地增强了语言的表达力,允许我们编写更灵活和强大的代码。现在,让我们通过一个具体的例子来展示如何将函数作为参数传递给其他函数。

举个例子:

go
package main import "fmt" func f2() int {    return 2 } // 函数也可以作为函数参数的类型 func f3(x func() int) {    ret := x()    fmt.Printf("f3打印ret的值:%v\n", ret)  //2    fmt.Printf("f3打印ret的类型:%T\n", ret) //int } func main() {    a := f2    fmt.Printf("a的类型:%T\n", a)    f3(a) }

打印结果如下:

函数也可以作为函数的返回值

当我们讨论函数作为参数时,我们已经看到了Go语言的灵活性和强大功能。但Go语言的函数特性不止于此,它们还可以作为其他函数的返回值。这种能力进一步扩展了函数式编程的概念,允许我们创建更加动态和可重用的功能。

现在,让我们通过一个实例来探索Go语言中函数作为返回值的用法。举个例子:

go
package main import "fmt" func f2() int {    return 2 } func ff(x, y int) int {    return x + y } // 函数不仅可以作为参数,还可以作为返回值 func f5(x func() int) func(int, int) int {    return ff } func main() {    f7 := f5(f2)    fmt.Printf("f7的值:%v\n",f7) //f7返回的是一个函数    fmt.Printf("f7的类型:%T\n", f7) }

打印结果如下:

总结:

  1. 我们打印f7的值是一个内存地址;
  2. f7的类型和我们预期的一致,返回了函数类型,就是我们定义的ff()函数。

进一步地,Go语言支持匿名函数和闭包。匿名函数没有名称,可以立即执行或赋值给变量,而闭包则是一个函数,它记住了创建时的环境,即使外部函数已经执行完毕。闭包使得变量的持久化和延迟计算成为可能,是实现复杂逻辑的强大工具。

匿名函数

匿名函数就是没有名字的函数,多用于实现回调函数和闭包。

在Go语言中函数内部不能再像之前那样定义函数了,只能定义匿名函数。

匿名函数的定义格式如下:

go
func(参数)(返回值){     函数体 }

匿名函数因为没有函数名,没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数:

go
func main() {         // 将匿名函数保存到变量         add := func(x, y int) {                 fmt.Println(x + y)         }         add(10, 20) // 通过变量调用匿名函数         //自执行函数:匿名函数定义完加()直接执行         func(x, y int) {                 fmt.Println(x + y)         }(10, 20) }

总结:自执行函数就是在匿名函数后面追加(),表示不需要外部调用,直接执行。

闭包

闭包是一个函数,这个函数包含了它外部作用域的一个变量。

举个例子:

go
package main import "fmt" func adder(x int) func(int) int {    return func(y int) int {       x += y       return x    } } func main() {    f1 := adder(1)    ret := f1(2)    fmt.Println(ret) }

打印结果如下:

总结:上面的例子就是一个典型的闭包结构:匿名函数内部包含了他外部的变量x

闭包=函数+引用环境

总结

Go语言通过其简洁而强大的函数特性,为开发者提供了高效的编程工具。函数不仅封装了逻辑,提高了代码的可读性和可维护性,而且Go支持函数作为参数和返回值,允许使用匿名函数和闭包,从而增强了代码的复用性和灵活性。这些特性使得Go语言在构建大型软件项目时尤为出色,能够实现复杂的功能抽象和模块化设计。

我写完回顾的时候觉得闭包的栗子有点晦涩,大家还有什么更好的方式解释闭包,欢迎在评论区留言。

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。

没准能让你能刷到自己意向公司的最新面试题呢。

感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:掘金面试群。

🚀 学习遇到瓶颈?想进大厂?

看完这篇技术文章,如果还是觉得不够系统,或者想在实战中快速提升?
王中阳的就业陪跑训练营,提供定制化学习路线 + 企业级实战项目 + 简历优化 + 模拟面试。

了解训练营详情