Golang 从入门到放弃 -0x07

数组、切片、map 的常见写法,以及切片共享底层数组这类高频坑。

这一章要讲三个高频选手:数组、切片、map。名字看着都认识,但第一次写的时候,尤其是切片,很多人都会有一种“这不是数组吗,怎么又不太像”的迷惑感。

数组:长度写死的老实人

Go 的数组长度是类型的一部分,这句话很重要。[3]int[4]int 不是同一个类型。

var nums [3]int
nums[0] = 10
nums[1] = 20
nums[2] = 30
fmt.Println(nums)

也可以直接初始化。

names := [3]string{"Go", "Python", "Java"}
fmt.Println(len(names))

不过说实话,数组在 Go 日常业务里存在感没有那么强。大部分时候,你真正天天打交道的是切片。

切片:真正常用的动态序列

切片可以理解成“对数组的一层更灵活的包装”。它不直接把数据全背在身上,而是描述一段连续的数据区域。

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

追加元素用 append

nums = append(nums, 4)
nums = append(nums, 5, 6)
fmt.Println(nums)

切片也可以从数组或者另一个切片里切出来。

arr := [5]int{10, 20, 30, 40, 50}
part := arr[1:4]
fmt.Println(part) // [20 30 40]

区间规则还是老朋友:左闭右开。

切片最容易踩的坑:共享底层数组

这是切片最值得早点知道的一件事。你以为你切出来的是副本,实际上很多时候只是同一块底层数据的不同窗口。

nums := []int{1, 2, 3, 4}
part := nums[1:3]
part[0] = 200
fmt.Println(nums) // [1 200 3 4]
fmt.Println(part) // [200 3]

如果你明确需要一份独立副本,就别偷懒,老老实实复制。

src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
dst[0] = 999
fmt.Println(src) // [1 2 3]
fmt.Println(dst) // [999 2 3]

make 是干嘛的

切片、map、channel 这几位,一般都喜欢用 make 创建。

scores := make([]int, 3, 5)
fmt.Println(scores)      // [0 0 0]
fmt.Println(len(scores)) // 3
fmt.Println(cap(scores)) // 5

这里长度是 3,容量是 5。容量可以先理解成“当前底层空间够你再塞几个”的意思,够用阶段知道这个就行,别一开始就和扩容算法死磕。

map:键值对老熟人

map 就是字典、哈希表、对象那一类亲戚,拿来存键值对最顺手。

ages := map[string]int{
    "raymond": 18,
    "tom":     20,
}

fmt.Println(ages["raymond"])

也可以先用 make 创建,再慢慢塞。

userAge := make(map[string]int)
userAge["alice"] = 21
userAge["bob"] = 22

取 map 的值时有个很经典的双返回值写法,用来判断 key 到底存不存在。

age, ok := userAge["jack"]
if ok {
    fmt.Println("年龄是", age)
} else {
    fmt.Println("查无此人")
}

删除元素用 delete

delete(userAge, "alice")

遍历

数组、切片、map 都可以配合 range 来遍历。

nums := []int{10, 20, 30}
for index, value := range nums {
    fmt.Println(index, value)
}

for key, value := range userAge {
    fmt.Println(key, value)
}

如果你不需要索引或者 key,可以用下划线占位。

for _, value := range nums {
    fmt.Println(value)
}

小结

如果只记一句话,那就是:

  • 数组长度固定,切片才是日常主力。
  • 切片很方便,但它可能共享底层数据。
  • map 用起来很爽,但取值时记得考虑 key 不存在的情况。

下一章开始讲 struct。也就是 Go 里“虽然我没有 class,但我照样能组织数据”的那一套。

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