Golang 从入门到放弃 -0x05

函数、多返回值、具名返回值、defer,以及 Go 里最基础的错误处理方式。

上一章把Go的骨架大概认全了,这一章终于轮到函数。函数这个东西大家都认识,但Go偏偏喜欢在“返回值”和“错误处理”上搞出一点自己的脾气,所以单独拎出来说很有必要。

函数长什么样

Go里定义函数用 func 关键字,格式非常直白。

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

同类型参数可以合并写,这也是你以后最常见的姿势。

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

调用就和别的语言差不多。

result := add(3, 5)
fmt.Println(result)

多个返回值

这是Go非常有代表性的特征之一。一个函数可以同时返回多个值,这不是语法糖,这是日常操作。

func swap(a, b string) (string, string) {
    return b, a
}
x, y := swap("hello", "world")
fmt.Println(x, y)

很多新手第一次看到会觉得有点怪,但你写几天后就会发现,这东西拿来返回结果加状态,实在太顺手了。

具名返回值

Go 允许你给返回值起名字。

func rectangle(width, height int) (area int, perimeter int) {
    area = width * height
    perimeter = 2 * (width + height)
    return
}

这个写法不是不能用,但我个人建议不要滥用。函数短一点还好,长一点就容易让读代码的人产生一种“你到底要 return 啥”的迷茫。除非返回值名字本身很有解释力,否则老老实实显式返回更清楚。

可变参数

如果你参数个数不固定,可以用 ...

func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}
fmt.Println(sum(1, 2, 3))
fmt.Println(sum(10, 20, 30, 40))

可变参数本质上就是一个切片,所以你也可以把现成的切片拆开传进去。

nums := []int{1, 2, 3}
fmt.Println(sum(nums...))

defer:先记账,后结算

defer 的意思可以粗暴理解成“先把这句登记一下,等当前函数快结束时再执行”。这个东西在资源释放、解锁、收尾日志里特别好用。

func demo() {
    fmt.Println("start")
    defer fmt.Println("clean up")
    fmt.Println("end")
}

执行顺序会是:

start
end
clean up

最常见的用法就是开完文件、拿完锁,立刻写一个 defer,避免你后面逻辑一复杂就忘了关。

file, err := os.Open("demo.txt")
if err != nil {
    return err
}
defer file.Close()

Go 的错误处理:没有 try/catch,只有老老实实 if err != nil

Go 不爱异常那一套。大部分业务错误都通过返回 error 来传出来,然后你自己判断。

package main

import (
    "errors"
    "fmt"
)

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为0")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("出错了:", err)
        return
    }
    fmt.Println("结果是:", result)
}

这里的套路非常固定:

  • 成功时返回正常结果和 nil
  • 失败时返回兜底值和一个具体的 error
  • 调用方拿到以后立刻判断 err

这种写法啰嗦吗?是有一点。但它的好处是,你一眼就知道哪段逻辑可能失败,错误是显式摆在台面上的,不是躲在角落里随时给你炸一下。

fmt.Errorf 也很常用

如果你想把上下文一起塞进错误信息里,fmt.Errorf 很方便。

func queryUser(id int) error {
    if id <= 0 {
        return fmt.Errorf("非法用户ID: %d", id)
    }
    return nil
}

一点点习惯问题

Go 社区对错误处理有一种近乎执念的朴素审美:能早点返回就早点返回,别把代码套成俄罗斯套娃。

func doWork() error {
    err := step1()
    if err != nil {
        return err
    }

    err = step2()
    if err != nil {
        return err
    }

    return nil
}

这类代码看起来平铺直叙,甚至有点像流水账,但维护起来真的轻松。业务代码不是写诗,少一点悬念反而是好事。

小结

这一章你至少要记住三件事:

  • Go 函数写法不复杂,但多返回值很常见。
  • defer 是个特别顺手的收尾工具。
  • Go 处理错误的主流姿势,就是 if err != nil

下一章我们聊指针。别怕,Go 里的指针没有 C 那么吓人,但它也绝不是摆设。

Read more

Harness Engineering:从驾驭模型到构建 AI 工厂

Harness Engineering:从驾驭模型到构建 AI 工厂

2026 年,AI 编程工具的竞争焦点发生了根本性转变:决定 AI 助手好不好用的,不再是模型本身,而是包裹在模型外面的那层"Harness"。同一个模型,在不同的 Harness 下,性能差距可以达到 78% vs 42%。 这篇文章将带你深入了解 Harness Engineering——这个正在重新定义 AI 工程实践的新兴领域。 一、什么是 Harness Engineering? Harness 的字面意思是"马具/缰绳"——用来驾驭一匹强壮但不受控的马。在 AI 语境下,Harness 就是 LLM 之外的一切:工具定义、记忆系统、权限模型、反馈循环、文档规范、多

By Fuyu Jia

Claude Code CLI + Ralph:让 AI 自动完成大型编程任务的终极方案

TL;DR 当你的编程任务大到一个 AI 对话窗口装不下时,Ralph 会帮你把任务拆成小块,让 Claude Code CLI 一个接一个地自动完成——每轮都用全新的上下文窗口,不会越写越糊涂。 一、什么是 Ralph? Ralph 是一个开源项目(GitHub 16k+ Stars),基于 Geoffrey Huntley 提出的 "Ralph Pattern" 构建。它的核心理念很简单: 不要让 AI 在一个漫长的会话里做完所有事情,而是把大任务拆成小故事,每个故事用一个全新的 AI 实例来完成。 这解决了 AI 编程中最常见的痛点——上下文窗口耗尽。当对话越来越长,AI 的输出质量会明显下降。Ralph 通过「每轮一个新实例」的方式,

By Fuyu Jia