Go 不推荐使用 this、self 等泛化名称作为方法接收者标识符,根本原因在于其违背 Go 的设计哲学:接收者本质是显式、可传递的首个参数,而非面向对象语境下的隐式上下文;统一使用 this 会模糊值/指针语义差异,损害代码清晰性与可维护性。
go 不推荐使用 `this`、`self` 等泛化名称作为方法接收者标识符,根本原因在于其违背 go 的设计哲学:接收者本质是显式、可传递的首个参数,而非面向对象语境下的隐式上下文;统一使用 `this` 会模糊值/指针语义差异,损害代码清晰性与可维护性。
在 Go 中,方法(method)并非传统 OOP 意义上的“类成员函数”,而是绑定到类型的函数——其接收者(receiver)在语法和语义上都等价于函数的第一个参数。这一点可通过 Go 的“去糖化”(desugaring)机制直观验证:
package main
import "fmt"
type Person struct {
Name string
Age int
}
// 值接收者方法
func (p Person) Greet() string {
return fmt.Sprintf("Hello, I'm %s", p.Name)
}
// 指针接收者方法
func (p *Person) GrowOld() {
p.Age++
}
func main() {
p := Person{Name: "Alice", Age: 30}
// 两种调用方式语义等价:
fmt.Println(p.Greet()) // 语法糖
fmt.Println(Person.Greet(p)) // 显式调用:接收者作为首参传入
p.GrowOld() // 修改原值
fmt.Printf("After growing old: %+v\n", p) // Age 变为 31
}这段代码清晰表明:p.Greet() 实质是 Person.Greet(p) 的语法糖,p 并非魔法变量,而是一个普通参数——它被复制传入(值接收者),或传入地址(指针接收者)。若强行命名为 this,不仅无法体现这种“参数本质”,反而会误导开发者:
- ❌ func (this Person) Greet() —— 暗示 this 总是指向当前实例,但实际 this 是副本,修改不影响原值;
- ❌ func (this *Person) GrowOld() —— 表面看合理,却掩盖了与值接收者的关键差异:同一名称承载两种截然不同的内存行为。
Go 官方《Code Review Comments》明确指出:
Don’t use generic names such as "me", "this" or "self" — identifiers typical of object-oriented languages that place more emphasis on methods as opposed to functions.
这背后有两大深层考量:
✅ 1. 哲学一致性:Go 是组合优先、函数为本的语言
Go 没有类、继承、访问修饰符或隐式 this 上下文。它通过结构体嵌套、接口实现和高阶函数达成抽象,强调显式优于隐式。将接收者命名为 p(Person)、c(Config)、r(Reader)或 srv(*Server),正是对这一原则的践行——名称反映身份与角色,而非强加 OOP 语义包袱。
✅ 2. 语义准确性:值 vs 指针,必须一目了然
接收者类型决定行为边界:
- func (s MyStruct) Do() → s 是副本,内部修改不生效;
- func (s *MyStruct) Do() → s 是指针,可修改原值。
使用中性缩写(如 s)配合显式的 * 符号,能无歧义传达意图;而 this 无论是否带 *,都天然暗示“当前对象”,极易引发误判。
✅ 推荐实践(简洁、一致、可读)
| 场景 | 推荐命名 | 说明 |
|---|---|---|
| 小型结构体(如 User, Config) | u *User, c Config | 单字母 + 类型首字母,小写,符合 Effective Go |
| 多字段复杂结构体 | cfg *Config, srv *Server | 稍具描述性,提升可读性,避免冗余 |
| 接口实现(如 io.Reader) | r io.Reader, w io.Writer | 社区约定俗成,一眼识别角色 |
| 避免 | this, self, me, obj, instance | 无信息量,违反 Go 命名哲学 |
// ✅ 清晰、地道、符合生态规范
func (u *User) Save(db *sql.DB) error {
return db.Save(u) // u 明确代表 *User 实例
}
func (c Config) Validate() error {
if c.Timeout <= 0 {
return errors.New("timeout must be positive")
}
return nil // c 是值,安全读取,不修改原配置
}⚠️ 注意事项
- 不要因“习惯其他语言”而妥协:从 Java/Python/JS 转来的开发者常本能使用 self,但这是 Go 代码审查中的高频否决点;
- 团队需统一风格:建议在 .golangci.yml 中启用 gosimple 或 revive 规则(如 receiver-naming),自动化拦截违规命名;
- 命名长度 ≠ 可读性:mySuperLongReceiverName 比 r 更差——Go 崇尚“短而达意”,1–3 字母是黄金长度。
遵循这些约定,不是教条主义,而是让代码真正“Go-like”:轻量、清晰、可组合、易协作。当你写下 func (s *Service) Start(),读者无需思考“s 是什么”,就能立即聚焦于逻辑本身——这正是 Go 工程师追求的终极可维护性。


















