Go 语言大白话入门 7 - 函数:把重复代码收起来

函数:把重复代码收起来

本章目标:把重复逻辑收进函数里,做到三件事就算过关:会写函数、会传参数、会接返回值。

常见坑位

  • 代码还没重复,就提前拆一堆函数,最后自己都看不懂。
  • 函数写好了,但忘了在 main 里调用,运行后啥都没发生。
  • 参数和返回值方向搞反:把"输入"写成"输出"。
  • 看见多返回值就紧张,其实就是"一个函数一次带回多个结果"。
  • 误以为函数里改了变量,外面一定会变。Go 默认是值传递,不一定会变。

先跑一个最小示例

先跑起来,再理解细节,这是最省时间的学习方式。

go 复制代码
package main

import "fmt"

func sayHello() {
    fmt.Println("你好,欢迎学习 Go")
}

func main() {
    sayHello()
    sayHello()
}

看到两行输出就说明你已经会"定义 + 调用"函数了。

带参数的函数

参数可以理解成"你喂给函数的数据"。

go 复制代码
package main

import "fmt"

func sayHi(name string) {
    fmt.Println("你好,", name)
}

func main() {
    sayHi("小张")
    sayHi("小刘")
}

这里 name string 的意思是:这个函数接收一个字符串类型的名字。

带返回值的函数

返回值就是"函数做完活后交回来的结果"。

go 复制代码
package main

import "fmt"

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

func main() {
    result := add(3, 5)
    fmt.Println(result) // 8
}

你可以把 add 理解成一个小工具:给它两个数,它回你一个和。

多返回值:Go 的高频写法

Go 很常见的一个特点是:一个函数可以返回多个值。

go 复制代码
package main

import "fmt"

func divide(a int, b int) (int, string) {
    if b == 0 {
        return 0, "不能除以零"
    }
    return a / b, ""
}

func main() {
    result, msg := divide(10, 2)
    fmt.Println(result, msg) // 5

    result2, msg2 := divide(10, 0)
    fmt.Println(result2, msg2) // 0 不能除以零
}

后面你会大量见到这种形式:

go 复制代码
value, err := someFunc()

前面是结果,后面是错误信息。下一章我们专门讲这个模式。

变长参数:参数个数不固定

当你不确定要传几个参数时,用 ...

go 复制代码
package main

import "fmt"

func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

func main() {
    fmt.Println(sum(1, 2, 3))         // 6
    fmt.Println(sum(10, 20, 30, 40))  // 100
}

nums ...int 在函数内部本质上就是 []int,这点后面学切片时会越用越顺。

匿名函数:临时用一次,不想起名

匿名函数就是"没有名字的函数"。

go 复制代码
package main

import "fmt"

func main() {
    greet := func(name string) {
        fmt.Println("你好,", name)
    }

    greet("小张")
    greet("小李")

    func() {
        fmt.Println("这段逻辑只执行一次")
    }()
}

以后在排序、HTTP 处理、goroutine 里,你会反复看到匿名函数。

闭包:匿名函数能记住外面的变量

go 复制代码
package main

import "fmt"

func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    next := counter()
    fmt.Println(next()) // 1
    fmt.Println(next()) // 2
    fmt.Println(next()) // 3
}

这里返回的匿名函数记住了 count,这就是闭包。

初学先记两点:

  • 闭包可以访问外层变量。
  • 闭包会让外层变量活得更久,别长期挂大对象。

函数还能当参数传来传去

Go 里函数也是"值",可以传给别的函数。

go 复制代码
package main

import "fmt"

func apply(nums []int, fn func(int) int) []int {
    result := make([]int, 0, len(nums))
    for _, n := range nums {
        result = append(result, fn(n))
    }
    return result
}

func main() {
    doubled := apply([]int{1, 2, 3}, func(n int) int {
        return n * 2
    })
    fmt.Println(doubled) // [2 4 6]
}

fn func(int) int 的意思是:这个参数本身是一个函数,输入 int,输出 int

值传递和引用类型,一次讲清

Go 只有值传递。

  • intstring、结构体:函数里改变量,外面通常不变。
  • slicemap:拷贝的是结构头,但底层数据共享,改元素外面能看到。

所以"函数里改了,外面会不会变",要看你传入的具体类型。

过关标准

你可以按这份清单自检:

  • 能自己写出并调用一个无参数函数。
  • 能写一个带参数函数,并传入不同数据。
  • 能写一个带返回值函数,并正确接收结果。
  • 看到 value, err := xxx() 不再慌。
  • 能说清"值传递"和"slice/map 的表现差异"。

练习任务

  1. 写一个 welcome(),打印一句欢迎语。
  2. 写一个 sayHi(name string),分别给两个名字打招呼。
  3. 写一个 max(a, b int) int,返回较大的那个数。
  4. 写一个 sum(nums ...int) int,输入任意个整数并求和。

下一章衔接

下一章我们就接着讲 Go 里最常见的错误处理模式:value, err := ... 到底该怎么写才稳。

本文章属于《Go语言大白话入门》零基础全套教程,持续更新、全程实操练手。 微信公众号【码栈研说】超前更新,目前比掘金领先 30 章内容,完整连载、无删减、持续日更,需要完整系统学习的读者可自行前往查看。

文中部分内容借助 AI 辅助梳理,全文人工校验、实操落地。

相关推荐
上进小菜猪7 小时前
把 KES 集群交给 Kubernetes 的九十天:一个 DBA 的试用实录
后端
两点王爷8 小时前
PostgreSQL 常用 SQL 语句与 GIS 相关函数详解
数据库·后端
考虑考虑8 小时前
Springboot环境变量占位符语法
spring boot·后端·spring
人邮异步社区8 小时前
学习Python的最佳学习路径是什么?
python·程序员
步行cgn10 小时前
Spring 基于 XML 的自动装配:byName 详解
java·后端·spring
RISCV_Explorer12 小时前
RISC-V启动与运行时规范机制解析——BRS约定、HSM多核启动与设备树要求
后端·risc-v
kyriewen12 小时前
我删掉了 29 个 AI Skill 里的 23 个:留下的 6 个都有同一个特点
人工智能·程序员·ai编程
星栈独行12 小时前
ADK-Rust 是什么?Rust 生态新一代 AI Agent 开发套件
人工智能·后端·rust
JavaGuide12 小时前
对标 MinIO!全新一代分布式文件系统正式发布
前端·后端
用户83562907805113 小时前
使用 Python 将 DOCX 转换为 Markdown
后端·python