核心心法:从 PHP 转 Go,最大的思维转变在于从“万能数组 (Array)”转向“严格类型 (Struct/Map)”以及理解“默认值传递”。


第一部分:指针 (Pointer)

1. 核心概念

Go 语言中的指针,本质上就是数据的内存地址

  • & (取址):获取“门牌号”(地址)。
  • * (解引用):拿着门牌号进屋,获取/修改里面的东西。

2. PHP 经验迁移

你的直觉非常准:Go 的指针 (*T) $\approx$ PHP 的引用 (&$v)

  • 共同目的:都是为了直接修改原始数据,而不是操作数据的副本 (Copy)。
  • 区别
    • PHPforeach ($arr as &$v) 是一种语法糖,PHP 帮你处理了地址。
    • Go:必须显式地传递地址 &v,并在函数内显式操作 *v

3. 对象传递的差异 (这也是最大的坑)

场景 PHP Go
传递对象 默认引用 (Class 实例默认就是引用) 默认复制 (Struct 默认是值拷贝)
如何修改 直接改 $obj->name 必须传指针 func(u *User)

4. 代码实战:如何正确修改数据

❌ 错误写法 (无效修改/只改了副本)

1
2
3
4
func modify(u User) { // 没加 *,这是值传递,复制了一份
u.Name = "New"
}
// 外部原来的 u 不会变

✅ 正确写法 (指针传递)

1
2
3
4
func modify(u *User) { // 加了 *,这是传地址
u.Name = "New"
}
// 外部原来的 u 变了

⚠️ 逻辑陷阱

1
2
3
4
5
6
7
8
func modify(u *User) {
// ❌ 误区:这样是创建了一个新对象,并没有修改原来的房子
// u = &User{Name: "Wrong"}

// ✅ 正确:直接通过指针修改原地址的值
u.Name = "Cola"
u.Age = 18
}

第二部分:数据结构 (Map vs Struct)

1. 为什么 Go 这么麻烦?

  • PHP (Array):像一个大麻袋,不管 Key 是什么,Value 是什么,随便往里塞,还可以无限套娃。
  • Go:像超市货架,必须分类。饮料区只能放饮料 (Type Safety)。

2. 什么时候用什么?(终极决策表)

数据特征 PHP 习惯 Go 最佳实践 典型例子
字段名固定 (已知结构) Array ['name'=>'x'] Struct (结构体) 用户信息、商品详情、登录参数
Key 不固定,但 Value 类型一样 Array Map (字典) 班级成绩单 name=>score、用户缓存 id=>User
纯列表 (无 Key) Array Slice (切片) [1, 2, 3]
完全未知/乱七八糟 Array Map + Interface 解析第三方未知的 JSON

3. 嵌套 Struct (解决复杂数据)

不要试图用 Map 去模拟 PHP 的多维数组,会写出地狱代码。用 Struct 像搭积木一样嵌套。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 好的设计:清晰、有自动补全、类型安全
type Wallet struct {
Balance float64
}

type User struct {
Name string
Wallet Wallet // Struct 套 Struct
}

func main() {
u := User{Name: "Cola", Wallet: Wallet{Balance: 100}}
fmt.Println(u.Wallet.Balance) // 爽点:直接点出来
}

第三部分:黄金法则 (Cheat Sheet)

📌 关于指针

  • 想在函数里修改外面的变量? $\rightarrow$ 传指针 (*T)。
  • 结构体很大,不想复制? $\rightarrow$ 传指针 (*T)。
  • 除此之外,优先用值传递。

📌 关于 Map vs Struct

问自己:“我在写代码时,能把 Key 的名字写死吗?”

  • 能写死 (如 Name, Age) $\rightarrow$ 定义为 Struct 的字段。
  • 不能写死 (如用户传来的 ID) $\rightarrow$ 定义为 Map 的 Key。

📌 关于 Interface

  • map[string]interface{} 是 Go 里的“PHP 数组模式”。
  • 不到万不得已(处理未知 JSON),尽量少用,因为取值时需要断言,非常麻烦。