go结构体需先type定义再声明变量,不可匿名;字段名大小写控制导出;字面量推荐按名赋值;大结构体或含mutex时用&person{};应使用带校验的工厂函数而非new。

Go 里创建结构体不是“调用某个函数”,而是先定义类型、再声明变量——没有构造函数,也没有内联匿名结构体语法,写错就会编译报错。
必须先用 type 定义结构体类型
常见错误是直接写 var u {Name string} 或 u := struct{...}{} 在变量声明位置——这会触发 expected type, found '{'。Go 要求所有结构体都得是命名类型。
- ✅ 正确:先
type User struct { Name string; Age int },再u := User{Name: "Tom"} - ❌ 错误:
u := struct{ Name string }{Name: "Tom"}(仅限函数内临时用,不能绑定方法、不能导出、不能作为字段类型) - 字段名首字母大小写决定是否可被其他包访问:大写(
Name)导出,小写(email)仅本包可用
Person{...} 字面量初始化的三种写法
结构体字面量最常用,但三种形式行为差异明显,尤其影响可维护性:
-
按字段名赋值(推荐):
p := Person{Name: "Alice", Age: 28}—— 字段顺序无关,新增字段不影响旧代码,未赋值字段取零值(Name="",Age=0) -
按定义顺序赋值(慎用):
p := Person{"Alice", 28}—— 必须填满所有字段,加个新字段就全得改,且无法跳过中间字段 -
零值初始化:
var p Person—— 所有字段为零值,适合后续逐步赋值,但容易漏设关键字段导致运行时 panic
什么时候该用 &Person{...} 而不是 Person{...}
返回指针不是为了“看起来高级”,而是解决两个实际问题:
- 避免拷贝:结构体较大(比如含
[]byte、map或嵌套深)时,值传递开销大;&Person{...}只传 8 字节地址 - 支持修改原值:方法接收者是
*Person时,必须传指针才能生效;否则p.Grow()修改的是副本,原结构体不变 - 含不可拷贝字段(如
sync.Mutex)的结构体,new(Person)或&Person{...}是唯一合法方式,否则编译报cannot copy sync.Mutex
别直接暴露字段,用工厂函数封装初始化逻辑
像 User{Name: "", ID: 0} 这种非法实例,靠文档或约定拦不住;工厂函数才是 Go 的惯用解法:
- 校验必要字段:
if opts.Name == "" { return nil, errors.New("Name required") } - 隐藏实现细节:比如内部用
passwordHash(小写),外部只通过NewUser(WithPassword("123"))注入 - 返回指针:
func NewUser(opts UserOptions) (*User, error)—— 值返回无法满足接口要求(如io.Writer需要指针接收者) - 避免
new(User):它只做内存分配、不执行任何逻辑,字段全零值,极易误用
最容易被忽略的一点:嵌套结构体字段如果没显式初始化,就是 nil 指针或空 map/slice,直接访问会 panic;比如 u.Addr.City 前没给 u.Addr 赋值,运行时就崩。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











