Go中访问结构体字段统一用.,无论变量是指针还是值;编译器自动解引用指针,无->操作符;nil指针调用.会panic;修改字段或避免大结构体复制时需指针接收者;取字段地址要求结构体本身可寻址。

用 -> 还是 .?Go 里没有 ->
Go 没有 C 那样的箭头操作符。无论变量是指针还是值,访问结构体字段统一用 .。编译器会自动解引用指针——这是 Go 的语法糖,不是隐式转换。
常见错误:写 ptr->Name 直接报错 syntax error: unexpected ->。别被其他语言习惯带偏。
-
person.Name和ptr.Name写法一样,只要ptr是*Person类型就合法 - 如果结构体字段未导出(小写开头),即使通过指针也无法在包外访问
- 对 nil 指针调用
.Field会 panic:panic: runtime error: invalid memory address or nil pointer dereference
什么时候必须用指针接收方法?
当方法需要修改结构体字段本身(不是副本)时,接收者必须是指针。值接收者操作的是副本,原结构体不变。
示例:
立即学习“go语言免费学习笔记(深入)”;
type Counter struct { n int }
func (c Counter) Inc() { c.n++ } // 无效:改的是副本
func (c *Counter) IncPtr() { c.n++ } // 有效:改的是原结构体
- 调用
c.Inc()后c.n不变;调用c.IncPtr()才真正自增 - 如果结构体较大(如含 slice、map 或大数组),指针接收可避免复制开销
- 实现接口时,若某方法用了指针接收者,那只有
*T能满足该接口,T不能
取地址和字段地址:&struct.Field 是合法的吗?
可以,但有严格限制:&s.Field 要求 s 本身必须是可寻址的(addressable)。常见不可寻址场景包括:
- 结构体字面量直接取字段地址:
&Person{Name:"A"}.Name→ 编译错误:cannot take the address of Person literal.Name - 函数返回结构体值:
&getPerson().Name同样非法 - 但
var p Person; &p.Name合法,因为p是变量,可寻址 - 指针解引用后字段可寻址:
ptr := &Person{}; &ptr.Name等价于&(*ptr).Name,合法
嵌套结构体字段的指针操作要注意什么?
嵌套字段访问依然只用 .,但空指针传播风险更高。例如 user.Profile.Address.City,只要中间任一环节是 nil(如 user.Profile == nil),就会 panic。
- 不要链式解引用前不做 nil 检查,尤其在 HTTP handler 或 JSON 解析后
- Go 1.19+ 可用
if addr := user.Profile?.Address; addr != nil { ... }(需启用go experiment fieldalignment?不,实际目前仍无安全链式操作符,此为误传;真实做法仍是显式判空) - 更稳妥写法:
if user.Profile != nil && user.Profile.Address != nil { fmt.Println(user.Profile.Address.City) } - 使用第三方库如
github.com/mitchellh/mapstructure或自定义 UnmarshalJSON 时,注意嵌套指针字段的零值处理逻辑
最易忽略的点:字段本身是指针类型(如 Name *string),这时 ptr.Name 得到的是 *string,再要取值得加一次 *,而很多人忘了这层间接性,直接当字符串用导致 panic 或空字符串。










