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 辅助梳理,全文人工校验、实操落地。

相关推荐
程序员天天困1 小时前
后端视角看 EventBus:发布订阅总线的原理、场景与用法
java·后端
ServBay1 小时前
WordPress 核心漏洞 wp2shell,波及超 5 亿网站
后端·php
分布式存储与RustFS2 小时前
RustFS Beta.10 性能解读:PUT 全面反超 MinIO,Rust 重写对象存储成了?
开发语言·后端·rust
Reart2 小时前
Leetcode 309.买卖股票的最佳时期含冷冻期(你也想成为股票高手吗o〃ω〃o,718)
后端
Reart3 小时前
Leetcode 188.买卖股票的最佳时机4(718)
后端·算法
金銀銅鐵3 小时前
[Python] 为 Vole 机器语言实现图形化界面
python·程序员
Reart3 小时前
Leetcode 123.买卖股票的最佳时期3(内有随心谈,718)
后端·算法
只与明月听3 小时前
LangChain 学习-掌握LangChain Core API
前端·人工智能·后端
无相求码4 小时前
数组越界为什么有时候不崩溃?VS2013 下栈上变量的幽灵布局解密
c语言·后端