010.Go语言中的面向对象

目录

1.Go语言中的面向对象

2.继承

3.聚合

4.方法

5.方法的重写

6.接口

7.多态

8.空接口

9.接口继承

10.接口断言

11.自定义类型和给类型起别名


1.Go语言中的面向对象

/*

1.概念:

		go不是一个面向对象的语言,可以使用结构体和接口模拟面向对象;面向对象的思想就是万物皆对象,
    不一步步的自己去做一些事情,而是根据相同事物的特性抽取出一个类, 通过类创建一个对象,由对象去完
    成这个功能。如:洗衣服不再一步步的自己洗,而是买个全自动洗衣机,让洗衣机去洗。

2.面向对象三大特性

	2.1:封装:
		    对象包括了属性和行为;Go语言通过结构体和接口实现封装,结构体封装了字段(属性),接口封
        装了方法(行为)。

	2.2:继承:
		    子类通过在结构体中定义父类的匿名字段实现封装;子类继承父类后就继承了父类定义的所有
        字段和方法;可以通过子类对象名.父类的属性或方法直接使用父类定义的字段和属性;结构体和接
        口都是可以多继承的。

	2.3:多态:
		    多态是指一个事物拥有多种形态,如动物包含了猫、狗、羊....,包括了向上转型和向下转型,
        多态默认就是向上转型(父类引用指向子类对象),如果向下转型(父类对象强转为子类对象),需要进行
        断言,否则可能出现错误。

*/

2.继承: 可以直接通过子类对象名.父类字段调用父类属性

//定义父类结构体

type Person struct {
	name string
	age  int
}

//定义子类结构体

type Student struct {
	Person // 通过定义父类的匿名字段实现继承
	school string
}

func main() {
	
	//1.定义单独的父类对象
	person := Person{
		name: "张三",
		age:  23,
	}
	fmt.Println(person)
	
	//2.定义子类对象
	student := Student{
		Person{
			name: "李四",
			age:  23,
		},
		"山东大学",
	}
	fmt.Println(student)
	fmt.Println(student.name)//注意: 继承之后可以直接通过子类对象名.父类字段调用父类属性

}

3.聚合:不能直接通过子类对象名.父类字段调用父类属性

type Address struct {
	city     string
	province string
}

//不使用匿名字段叫聚合,不能使用子类对象名.父类属性进行使用

type Person struct {
	name    string
	age     int
	address Address
}

func main() {
	person := Person{
		name: "张三",
		age:  23,
		address: Address{
			city:     "菏泽市",
			province: "山东省",
		},
	}
	fmt.Println(person)
	//fmt.Println(person.city)//不能使用
	fmt.Println(person.address.province)
}

4.方法

/*

	在Go语言只能够函数和方法不是一个东西;函数是一段独立功能的代码,方法是指定调用者的一段独立功能的代码,不同调用者之间方法名可以重复。
	格式:
	func (结构体名称 结构体) 方法名(){
		//方法体
	}

*/

//定义结构体

type Dog struct {
	name string
	age  int
}
type Cat struct {
	name string
	age  int
}

// 定义方法

func (dog Dog) eat() {
	fmt.Println(dog.name, "吃骨头")
}

func (cat Cat) eat() {
	fmt.Println(cat.name, "吃鱼")
}

func (cat Cat) sleep() {
	fmt.Println(cat.name, "睡着了")
}
func main() {
	
	//创建一个狗
	dog := Dog{"大黄", 2}
	dog.eat()
	//创建一个猫
	cat := Cat{"大花", 3}
	cat.eat()
	cat.sleep()

}

5.方法的重写

/*
	方法重写:在父子关系中,方法名称相同叫做重写,方法重写是基于继承的
*/

//定义父结构体

type Animal struct {
	name string
	age  int
}

//定义子结构体

type Dog struct {
	Animal
}

type Cat struct {
	Animal
}

//定义父类方法

func (animal Animal) eat() {
	fmt.Println(animal.name, "吃东西")
}

// 子类重写父类方法

func (dog Dog) eat() {
	fmt.Println(dog.name, "吃骨头")
}

func (cat Cat) eat() {
	fmt.Println(cat.name, "吃鱼")
}

// 子类除了重写父类方法还可以有自己的方法

func (cat Cat) sleep() {
	fmt.Println(cat.name, "睡觉")
}

func main() {

	// 创建一个动物对象
	animal := Animal{
		name: "动物",
		age:  2,
	}
	animal.eat()
	
	// 创建一个猫对象
	cat := Cat{
		Animal{
			"大花",
			3,
		},
	}
	cat.eat()
	cat.sleep()
}

6.接口

/*
	结构体用于定义属性,接口用于定义方法;接口只定义方法,不做方法的实现,结构体实现接口中的所有方法就叫实现了接口;
*/

// 定义接口

type Usb interface {
	Input()
	Output()
}

//定义结构体

type Mouse struct {
	brand string
}

type Keyboard struct {
	brand string
}

// 结构体重写接口中的所有方法来实现接口

func (mouse Mouse) Input() {
	fmt.Println(mouse.brand, "鼠标输入")
}

func (mouse Mouse) Output() {
	fmt.Println(mouse.brand, "鼠标输出")
}

func (keyboard Keyboard) Input() {
	fmt.Println(keyboard.brand, "键盘输入")
}

func (keyboard Keyboard) Output() {
	fmt.Println(keyboard.brand, "键盘输出")
}

// 定义一个测试函数,传递usb的实现类,自动去判断类型调用相应的方法

func test(usb Usb) {
	usb.Input()
	usb.Output()
}

func main() {

	//创建一个鼠标对象
	mouse := Mouse{"罗技"}
	test(mouse)

	//创建一个键盘对象
	keyboard := Keyboard{"樱桃"}
	test(keyboard)

}

7.多态

/*
	多态: 父类引用指向子类对象
*/

//定义父类接口

type Animal interface {
	eat()
	sleep()
}

// 定义子类结构体

type Dog struct {
	name string
	age  int
}

type Cat struct {
	name string
	age  int
}

//结构体实现重写接口中所有的方法以实现接口

func (dog Dog) eat() {
	fmt.Println(dog.name, "吃骨头")
}

func (dog Dog) sleep() {
	fmt.Println(dog.name, "睡着了")
}

func (cat Cat) eat() {
	fmt.Println(cat.name, "吃鱼")
}

func (cat Cat) sleep() {
	fmt.Println(cat.name, "睡着了")
}

func main() {
	
	//多态
	var animal Animal = Dog{"大黄", 2}
	animal.eat()   // 调用到的是子类重写后的方法
	animal.sleep() // 调用到的是子类重写后的方法
}

8.空接口

/*
	    空接口:实现一个接口就要实现它的所有方法;空接口没有方法,所以所有的东西都实现了空接口,任意
    类型都可以赋值给空接口,空接口作为函数的参数可以传递任意类型的数据,空接口还有一个别名叫any。
*/

//定义一个空接口
type I interface {
}

//定义结构体
type Person struct {
	name string
	age  int
}

//定义一个测试函数,空接口作为参数,可以传递任意类型的数据
func test1(i I) {
	fmt.Println(i)
}

// 或者直接传递空接口
func test2(i interface{}) {
	fmt.Println(i)
}
func main() {

	//1.所有的东西都实现了空接口,任意类型都可以赋值给空接口
	var i1 I = "字符串"
	var i2 I = 3.14
	var i3 I = true
	var i4 I = Person{"张三", 23}
	fmt.Println(i1, i2, i3, i4)
	fmt.Println("----------")

	//2.空接口作为函数的参数可以接收任意类型的数据
	test1("测试")
	test1(6.66)
	test2(false)
	test2(Person{"李四", 24})
	fmt.Println("----------")

	//3.空接口的别名any做map的值类型,map可以保存任意类型的数据
	map1 := make(map[string]any)
	map1["name"] = "王五"
	map1["age"] = 25
	map1["nv"] = Person{"女朋友", 18}
	fmt.Println(map1)
	fmt.Println("----------")

	//4.空接口的别名any做slice的值类型,slice可以保存任意类型的数据
	s1 := make([]any, 0)
	s1 = append(s1, "字符串", 1, 3.14, true, Person{"赵六", 26})
	fmt.Println(s1)
}

9.接口继承:接口可以继承,还可以多继承

// 定义接口

type A interface {
	testA()
}

type B interface {
	testB()
}

type C interface {
	A
	B
	testC()
}

//定义结构体

type Str struct {
}

//结构体实现接口

func (str Str) testA() {
	fmt.Println("testA")
}
func (str Str) testB() {
	fmt.Println("testB")
}
func (str Str) testC() {
	fmt.Println("testC")
}
func main() {
	
	//子类可以调用实现的所有方法
	str := Str{}
	str.testA()
	str.testB()
	str.testC()
	
	//多态:只能调用父接口有的方法
	var a A = Str{}
	a.testA()
	
	var b B = Str{}
	b.testB()
	
	var c C = Str{}
	c.testA()
	c.testB()
	c.testC()
}

10.接口断言:向下转型前需要断言,防止代码报错

//定义接口
type USB interface { //重写接口的所有方法可以实现接口
	Input()
	Output()
}

// 定义结构体
type Mouse struct {
	Brand string
}

type Keyboard struct {
	Brand string
}

//结构体重写接口中所有的方法以实现接口
func (mouse Mouse) Input() {
	fmt.Println(mouse.Brand + "鼠标输入")
}
func (mouse Mouse) Output() {
	fmt.Println(mouse.Brand + "鼠标输出")
}
func (mouse Mouse) ToString() {
	fmt.Println("我是鼠标")
}

func (keyboard Keyboard) Input() {
	fmt.Println(keyboard.Brand + "键盘输入")
}
func (keyboard Keyboard) Output() {
	fmt.Println(keyboard.Brand + "键盘输出")
}

func (keyboard Keyboard) ToString() {
	fmt.Println("我是键盘")
}


//类型转换  变量名 := 对象名.(目标类型)
func main() {

	//多态的向下转型和断言:多态向下转型可能报错,需要断言
	var usb1 USB = Mouse{"达尔优"}
	fmt.Println(usb1)
	var usb2 USB = Keyboard{"雷蛇"}
	fmt.Println(usb2)
	fmt.Println("========")
	//向下转型:方式一,通过状态判断是不是某个类型
	v, ok := usb1.(Mouse)
	//v, ok := usb2.(Mouse)
	if ok {
		v.Input()
		v.Output()
		v.ToString()
	} else {
		fmt.Println("对象不是鼠标")
	}
	fmt.Println("========")
	//向下转型:方式二,通过类型匹配到后,需要再转换成响应类型,不然调用不到子类特有的方法
	convert(usb2)

}
func convert(para any) {
	switch para.(type) {

	case pojo.Mouse:
		mouse := para.(Mouse)
		mouse.Input()
		mouse.Output()
		mouse.ToString()

	case pojo.Keyboard:
		keyboard := para.(Keyboard)
		keyboard.Input()
		keyboard.Output()
		keyboard.ToString()
	default:
		fmt.Println("未找到类型")
	}
}

11.自定义类型和给类型起别名


//自定义类型:是一种新的类型,不同类型之间不能运算

type DiyInt int

// 给int起个别名还是int类型

type MyInt = int

func main() {

	var i int = 10
	var di DiyInt = 20
	//fmt.Println(i + di) // 不同类型之间不能运算 invalid operation: i + di (mismatched types int and DiyInt)
	fmt.Println(i + int(di)) //可以强转为同一类型后进行运算

	var mi MyInt = 30 // 这个是起别名,还是int类型,相同类型之间可以运算
	fmt.Println(i + mi)

}
<think>嗯,用户现在想了解Go语言中实现面向对象的机制和方法,特别是struct、interface、方法嵌套这些方面。用户之前已经问过关于make和new的区别,现在转向面向对象的实现,可能是在学习Go的核心特性。 首先,我需要回顾用户提供的引用内容。引用1提到Go的interface是实现多态的关键,struct和interface的组合代替了传统的继承。引用2和3详细说明了struct的作用,类似于其他语言的类,可以包含字段和方法,同时提到struct是值类型。引用4总结了方法、接口和嵌入类型如何共同工作,实现抽象和扩展性。 用户的问题集中在Go如何通过struct、interface和方法嵌套来实现面向对象。需要分步骤解释这些机制,并结合示例代码。可能用户对传统面向对象概念(如继承、多态)在Go中的不同实现方式感到困惑,需要明确说明Go的组合思想。 首先,结构体(struct)作为自定义类型的基础,替代了类。需要说明如何定义struct,添加方法,以及值类型的特点。然后,接口(interface)的作用,如何实现多态,解耦依赖。接着,方法嵌套和嵌入结构体,如何实现类似继承的效果,但实际是组合。 需要注意用户可能对Go没有传统继承机制感到疑惑,需要强调组合优于继承的原则。同时,接口的隐式实现特性,不同于Java等显式声明,这点需要举例说明。 在组织回答时,结构要清晰,分点讲解每个机制,对比传统OOP,给出代码示例。最后总结Go面向对象特点,强调组合和接口多态的优势。可能还需要解答常见疑问,比如如何实现多态,没有继承怎么办,接口的使用场景等。 需要确保回答准确,引用之前的引用内容,但不过度依赖,保持自然。同时,用户可能希望了解实际应用场景,比如如何设计可扩展的结构,如何利用接口进行测试等。因此,在示例中可以包含实际用例,如不同支付方式的实现,展示多态的应用。 最后,检查是否有遗漏点,比如方法接收者的类型(值vs指针),接口的动态调用机制,嵌入结构体的方法提升等。确保覆盖用户可能关心的所有方面,并提供足够详细的解释和示例,帮助用户理解Go面向对象实现方式。</think>### Go语言面向对象实现深度解析 Go语言通过**结构体(struct)**、**接口(interface)** 和 **方法(method)** 实现面向对象特性,但其设计理念与传统OOP语言(如Java)有显著差异。以下从核心机制到具体实现进行分层解析: --- #### 一、结构体(struct):类(class)的替代者 1. **定义与特性** ```go type User struct { Name string // 公开字段 age int // 私有字段(仅包内可见) Address // 嵌入结构体(组合特性) } type Address struct { City string } ``` - **数据封装**:通过大小写控制字段/方法的可见性(如`Name`公开,`age`私有)[^3] - **值类型**:赋值或传参时默认复制整个结构体(需用指针修改原对象) - **方法绑定**:通过接收者(receiver)关联方法 ```go func (u *User) SetName(name string) { u.Name = name // 指针接收者可修改原对象 } ``` 2. **与传统类的对比** | 特性 | Go结构体 | 传统类 | |------------------|------------------------|-------------------| | 继承 | 通过嵌入实现组合 | 显式继承 | | 多态 | 依赖接口实现 | 通过虚函数/重写 | | 访问控制 | 大小写控制可见性 | public/protected/private | | 实例化 | 值类型或指针 | 引用类型 | --- #### 二、接口(interface):多态的核心载体 1. **隐式实现机制** ```go type Speaker interface { Speak() string } type Dog struct{} func (d Dog) Speak() string { return "Woof!" } // 自动实现Speaker接口 ``` - **鸭子类型**:只要类型实现了接口方法,即视为实现该接口[^1] - **解耦设计**:接口定义行为契约,与具体实现分离 2. **多态实现示例** ```go func MakeSound(s Speaker) { fmt.Println(s.Speak()) } func main() { MakeSound(Dog{}) // 输出: Woof! MakeSound(Cat{}) // 假设Cat也实现了Speaker } ``` --- #### 三、方法嵌套与组合:替代继承的核心手段 1. **嵌入结构体(组合)** ```go type Animal struct { Name string } func (a Animal) Move() { fmt.Println("Moving") } type Bird struct { Animal // 嵌入结构体(非继承) WingSpan int } func main() { b := Bird{Animal: Animal{"Sparrow"}, WingSpan: 15} b.Move() // 直接调用嵌入结构体的方法 } ``` - **方法提升**:嵌入结构体的方法会被提升到外层类型 - **覆盖机制**:可重新定义同名方法实现"覆盖" ```go func (b Bird) Move() { fmt.Println("Flying") } ``` 2. **接口组合** ```go type Reader interface { Read() } type Writer interface { Write() } type ReadWriter interface { Reader Writer // 组合多个接口 } ``` --- #### 四、完整面向对象示例:支付系统设计 ```go // 定义接口 type Payment interface { Process(amount float64) error } // 结构体实现 type CreditCard struct{ Balance float64 } func (c *CreditCard) Process(amt float64) error { if c.Balance < amt { return errors.New("余额不足") } c.Balance -= amt return nil } type Alipay struct{ AccountID string } func (a Alipay) Process(amt float64) error { fmt.Printf("支付宝账户%s扣款%.2f\n", a.AccountID, amt) return nil } // 多态调用 func HandlePayment(p Payment, amt float64) { if err := p.Process(amt); err != nil { fmt.Println("支付失败:", err) } } ``` --- #### 五、与传统OOP的关键差异 | 特性 | Go语言实现方式 | 传统OOP实现方式 | |---------------------|----------------------------|----------------------| | **继承** | 通过组合和接口实现 | 类继承机制 | | **多态** | 接口隐式实现 | 显式继承+方法重写 | | **封装** | 包级可见性控制 | 访问修饰符 | | **抽象** | 接口定义行为契约 | 抽象类/接口 | --- ### 核心结论 1. **组合优于继承**:通过结构体嵌入和方法提升实现代码复用[^3][^4] 2. **接口驱动设计**:利用接口实现松耦合和多态[^1][^4] 3. **显式定义行为**:通过方法接收者明确操作对象(值或指针) --- ### 相关问题 1. Go语言中如何实现类似父类方法调用的效果? 2. 接口的空接口(`interface{}`)有什么特殊用途? 3. 结构体指针接收者与值接收者的选择标准是什么? 4. Go语言如何通过接口实现依赖注入? : 接口与多态实现 [^2]: 结构体基础定义 [^3]: 方法绑定与可见性控制 [^4]: 组合与接口的协作机制
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值