GO_面向对象_方法

一、Go 方法核心概念

1. 方法本质

方法本质是函数 ,但必须和特定类型绑定 (区别于普通函数),是 Go 实现面向对象++封装++的核心手段。

2. 函数 vs 方法 语法对比

go

Go 复制代码
// 1. 普通函数(无类型绑定)
func 函数名(参数) 返回值 {}

// 2. 匿名函数
func() {}

// 3. 方法(绑定指定类型,必须有接收者)
func (接收者变量 绑定类型) 方法名(参数) 返回值 {}
  • 接收者:相当于方法的第一个参数,是绑定类型的实例
  • 只有绑定了类型的函数,才能叫方法

3. 方法的意义:实现封装

普通函数没有 "归属",方法可以给类型绑定专属函数,就像机器的按钮,隐藏内部实现,对外提供操作接口。


二、方法基础使用

1. 给自定义类型绑定方法

go

Go 复制代码
package main

import "fmt"

// 自定义类型
type long int

// 普通函数:面向过程
func Add01(a, b long) long {
	return a + b
}

// 方法:给long类型绑定,面向对象
// tmp:接收者,相当于参数
func (tmp long) Add02(other long) long {
	return tmp + other
}

func main() {
	// 调用普通函数
	res1 := Add01(1, 1)
	fmt.Println("函数调用:", res1)

	// 调用方法:变量名.方法名()
	var a long = 2
	res2 := a.Add02(3)
	fmt.Println("方法调用:", res2)
}

核心:面向对象只是换了一种调用方式,本质还是函数。

2. 给结构体类型绑定方法(最常用)

结构体是 Go 中最常用的绑定类型,可实现属性 + 方法的封装:

go

Go 复制代码
type Person struct {
	name string
	sex  byte
	age  int
}

// 绑定打印方法
func (tmp Person) PrintInfo() {
	fmt.Println("成员信息:", tmp)
}

// 绑定赋值方法
func (p *Person) SetInfo(n string, s byte, a int) {
	p.name = n
	p.sex = s
	p.age = a
}

func main() {
	// 初始化结构体
	p := Person{"mike", 'm', 18}
	p.PrintInfo() // 调用方法

	// 指针接收者方法调用
	var p2 Person
	(&p2).SetInfo("yoyo", 'f', 22)
	p2.PrintInfo()
}

三、方法使用规则

1. 接收者类型限制

  1. 接口类型不能作为接收者
  2. 接收者的基础类型本身不能是指针

go

Go 复制代码
// 错误写法:类型本身是指针,不能做接收者
type pointer *int
func (tmp pointer) test() {}

// 正确写法:接收者是指针类型(推荐)
type long int
func (tmp *long) test02() {}

2. 不支持重载,支持同名方法

Go不支持函数重载 ,但接收者类型不同,同名方法不算重载,是独立方法:

go

Go 复制代码
type long int
type char string

// 两个test方法,接收者不同,相互独立
func (tmp long) test() {}
func (tmp char) test() {}

四、值接收者 vs 指针接收者(核心重点)

1. 本质区别:值传递 vs 指针传递

类型 传递方式 效果 使用场景
值接收者 值拷贝 方法内修改,不影响原变量 只读操作、小型结构体
指针接收者 引用传递 方法内修改,直接修改原变量 修改成员、大型结构体、提升效率

2. 代码示例

go

Go 复制代码
type Person struct {
	name string
	age  int
}

// 值接收者:值传递,拷贝副本
func (p Person) SetInfoValue(n string, a int) {
	p.name = n
	p.age = a
}

// 指针接收者:引用传递,操作原变量
func (p *Person) SetInfoPointer(n string, a int) {
	p.name = n
	p.age = a
}

func main() {
	s1 := Person{"go", 22}
	
	// 值接收者:不修改原变量
	s1.SetInfoValue("mike", 18)
	fmt.Println(s1) // 输出:{go 22}

	// 指针接收者:修改原变量
	(&s1).SetInfoPointer("mike", 18)
	fmt.Println(s1) // 输出:{mike 18}
}

五、方法集(自动类型转换)

Go 编译器会自动转换接收者类型,无需严格遵守方法集约束:

  1. 指针类型变量,可以调用值接收者 + 指针接收者方法
  2. 普通类型变量,可以调用值接收者 + 指针接收者方法

go

Go 复制代码
type Person struct {
	name string
}

func (p Person) SetInfoValue()  {} // 值接收者
func (p *Person) SetInfoPointer() {} // 指针接收者

func main() {
	// 指针变量:调用两种方法
	p1 := &Person{"mike"}
	p1.SetInfoValue()
	p1.SetInfoPointer()

	// 普通变量:调用两种方法
	p2 := Person{"mike"}
	p2.SetInfoValue()
	p2.SetInfoPointer() // 编译器自动转换为 (&p2).SetInfoPointer()
}

六、方法的继承与重写

1. 方法继承:通过匿名字段实现

结构体嵌套匿名结构体,自动继承匿名结构体的所有成员和方法

go

Go 复制代码
// 父结构体
type Person struct {
	name string
	age  int
}

// 父结构体方法
func (tmp *Person) PrintInfo() {
	fmt.Printf("姓名:%s,年龄:%d\n", tmp.name, tmp.age)
}

// 子结构体:嵌套Person(匿名字段),实现继承
type Student struct {
	Person // 匿名字段
	id     int
	addr   string
}

func main() {
	s := Student{Person{"mike", 18}, 666, "北京"}
	s.PrintInfo() // 直接调用继承的方法
}

2. 方法重写:就近原则

子结构体定义和父结构体同名的方法,就是方法重写:

  • 调用时:优先调用自身方法(就近原则)
  • 强制调用父类方法:子变量.父结构体.方法()

go

Go 复制代码
// 子结构体重写方法
func (tmp *Student) PrintInfo() {
	fmt.Println("学生信息:", tmp)
}

func main() {
	s := Student{Person{"mike", 18}, 666, "北京"}
	
	// 就近原则:调用子结构体方法
	s.PrintInfo()
	
	// 显式调用父结构体方法
	s.Person.PrintInfo()
}

七、方法值 & 方法表达式

1. 方法值

将方法赋值给变量,隐藏接收者,直接调用变量即可:

go

Go 复制代码
func main() {
	p := Person{"mike", 18}
	
	// 传统调用
	p.SetInfoPointer()

	// 方法值:绑定接收者,直接调用
	pFunc := p.SetInfoPointer
	pFunc() // 等价于 p.SetInfoPointer()

	vFunc := p.SetInfoValue
	vFunc()
}

2. 方法表达式

显式传递接收者,格式:(类型).方法名

go

Go 复制代码
func main() {
	p := Person{"mike", 18}
	
	// 指针接收者方法表达式
	f1 := (*Person).SetInfoPointer
	f1(&p) // 显式传接收者

	// 值接收者方法表达式
	f2 := (Person).SetInfoValue
	f2(p)
}

八、核心总结

  1. 方法 = 绑定类型的函数,是 Go 封装的核心,接收者是方法第一个参数
  2. 值接收者 :拷贝副本,不修改原变量;指针接收者:引用传递,修改原变量
  3. 编译器自动转换接收者类型,方法集无严格调用限制
  4. 匿名字段实现方法继承 ,同名方法实现方法重写(就近原则)
  5. 方法值 / 表达式:简化方法调用,灵活使用
相关推荐
布朗克1681 小时前
Go 入门到精通-16-字符串深入
开发语言·后端·golang·字符串
北冥you鱼1 小时前
Go flag 包详解:从命令行解析到实战应用
开发语言·后端·golang
web守墓人2 小时前
【python】uv解决依赖安装缓慢的问题
开发语言·python·uv
geovindu3 小时前
CSharp: Bridge Pattern
开发语言·后端·桥接模式·结构型模式
এ慕ོ冬℘゜4 小时前
深入 JavaScript BOM:掌握 window 对象的窗口控制魔法
开发语言·javascript·ecmascript
2501_941982054 小时前
企业微信二次开发:如何用 Python 搭建通用的 Webhook 实时消息接收
开发语言·python·企业微信
逝水无殇4 小时前
C# 特性详解
开发语言·后端·c#
灵晔君4 小时前
【C++】二叉搜索树
开发语言·c++
LongtengGensSupreme5 小时前
C#图像内存高速拷贝:使用Marshal.AllocHGlobal与ArrayPool实现内存拷贝的几个方法
开发语言·数码相机·c#