go语言的面向对象详解
1.go语言面向对象的概念
GO语言的面向对象与传统的java、C#是不一样的。GO里面没有CLASS类的概念。GO语言里使用了结构体替代了class,使用首字母大写来公开对象与方法。GOlang支持面向对象的特性,但并不是纯粹的面向对象语言。GO去掉了传统OOP语言的继承(extends)、方法重载、构造和析构(destructor)函数、隐藏this指针等关键字。
GO语言仍然有编程的继承、封闭和多态的特性,但GO使用了更优雅的接口方式来关联降低耦合性,使用更灵活,GO语言在面向接口编程是非常重要的特性!
面向对象有三个基本特征,封装、继承、多态。
- 封装就是隐藏对象的属性和实现细节,仅对外公开接口(这里只是广义概念,不是指Interface,是说大写字母开头的方法),控制在程序中属性的读和修改的访问级别。
- 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
- 多态就是同一个行为具有多个不同表现形式或形态的能力。是指一个类实例(对象)的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
封装
封装是OOP的一个核心概念,指的是将数据(属性)和操作这些数据的方法(行为)捆绑在一起,并对外部隐藏内部实现细节。在Go语言中,封装主要通过包(package)和可见性规则来实现:
1. 包(Package):Go语言通过包来组织代码。每个包可以包含多个文件,这些文件共享同一个命名空间。包的名称通常是其导入路径的最后一个元素。
2. 可见性规则:Go语言使用首字母大小写来控制变量、类型、函数等的可见性。如果一个标识符以大写字母开头,那么它是公开的(exported),可以在包外访问;如果以小写字母开头,则仅在包内可见。
package myPackage
// Public function
func PublicFunc() {
// ...
}
// Private function
func privateFunc() {
// ...
}
在上面的例子中,PublicFunc 是公开的,可以在其他包中被访问,而 privateFunc 只能在 myPackage 包内部访问。
go和其他语言不同,struct关键字只能定义属性,但是不支持行为,也就是不能定义方法。golang既然支持面向对象那么肯定是能支持方法的,只不过是写法稍微有些不同。 golang是通过下面的方式进行方法绑定的
func (this *Person) GetName() {
fmt.Printf(this.Name)
}
func main(){
person := Person{
Name: "xiaofan",
Age: 18, }
person.GetName() //执行Person绑定的方法GetName return}
(this *Person)
(this *Person)中的this只是一个变量,你不用this,写成(a *Person) 或者(p *Person)也是可以的
this *Person的含义为 this = *Person,也就是说把结构体Person的指针指向了this
this *Person中Person必须传指针类型,如果写成(this Person)就相当于把Person结构体拷贝了一份给this,那么this在方法中做任何操作都是和结构体没有任何关系的了。
继承
Go语言没有传统意义上的类(class)和继承(inheritance)。但是,Go通过接口(interface)和嵌入(embedding)提供了一种替代方案:
1. 接口(Interface):Go中的接口是一种类型,它定义了一组方法签名。任何实现了这些方法的类型都被认为是实现了该接口。这类似于其他语言中的“鸭子类型”或“结构化类型”。
当然,Go中是没有类的,不过,我们可以通过结构体来模拟这些特征。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 任何实现了Reader和Writer接口的类型都可以被认为是实现了ReadWriter接口
type ReadWriter interface {
Reader
Writer
}
2. 嵌入(Embedding):Go 1.18版本引入了类型嵌入,允许将一个类型嵌入到另一个类型中,从而复用字段和方法。
type Base struct {
// Base fields
}
func (b *Base) BaseMethod() {
// Base method
}
type Derived struct {
*Base // 嵌入Base类型
}
// 通过嵌入,Derived类型隐式地拥有了Base的字段和方法
下面是具体的实现方法
package main // 声明当前文件属于哪个包
import (
"fmt" // 导入"fmt"包,用于输出
)
type Tree struct { // 定义一个结构体Tree,包含三个字段:Value(整型),Left(指向Tree的指针),Right(指向Tree的指针)
Value int // 节点的值
Left *Tree // 指向左子树的指针
Right *Tree // 指向右子树的指针
}
func (t Tree) setValue1(v int) { // 定义一个方法setValue1,接收一个整型参数v,t是Tree类型的值接收者
t.Value = v // 修改t的Value字段为v,由于t是值接收者,这里的修改不会影响调用该方法时传入的Tree实例
}
func (t *Tree) setValue2(v int) { // 定义一个方法setValue2,接收一个整型参数v,t是Tree类型的指针接收者
t.Value = v // 修改t指向的Tree实例的Value字段为v,由于t是指针接收者,这里的修改会直接影响调用该方法时传入的Tree实例
}
func main() { // 主函数,程序的入口
t1 := Tree{ // 创建一个Tree类型的实例t1
Value: 0, // 初始化Value字段为0
Left: nil, // 初始化Left字段为nil,表示没有左子树
Right: nil, // 初始化Right字段为nil,表示没有右子树
}
t1.setValue1(1) // 调用setValue1方法,传入参数1,由于是值接收者,不会修改t1的Value字段
fmt.Println(t1) // 输出t1的值,由于Value字段没有被修改,输出结果为{0 <nil> <nil>}
t1.setValue2(2) // 调用setValue2方法,传入参数2,由于是指针接收者,会修改t1的Value字段
fmt.Println(t1) // 输出t1的值,Value字段被修改为2,输出结果为{2 <nil> <nil>}
t2 := &Tree{ // 创建一个Tree类型的指针t2,指向一个Tree实例
Value: 0, // 初始化Value字段为0
Left: nil, // 初始化Left字段为nil,表示没有左子树
Right: nil, // 初始化Right字段为nil,表示没有右子树
}
t2.setValue1(1) // 调用setValue1方法,传入参数1,由于是值接收者,不会修改t2指向的Tree实例的Value字段
fmt.Println(t2) // 输出t2指向的Tree实例的值,由于Value字段没有被修改,输出结果为&{0 <nil> <nil>}
t2.setValue2(2) // 调用setValue2方法,传入参数2,由于是指针接收者,会修改t2指向的Tree实例的Value字段
fmt.Println(t2) // 输出t2指向的Tree实例的值,Value字段被修改为2,输出结果为&{2 <nil> <nil>}
}
运行结果:
{0 <nil> <nil>}
{2 <nil> <nil>}
&{0 <nil> <nil>}
&{2 <nil> <nil>}
2.go语言的method继承
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human // 匿名字段
school string
}
type Employee struct {
Human // 匿名字段
company string
}
// 在 human 上面定义了一个 method
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
3.结构体的几种定义形式:
package main
import "fmt"
type Student struct {
Name, StuNum, Address string //批量定义三个String类型
}
type miniStudent struct {
stu Student //继承Student 的所有属性
Age int //年龄
Scores [2]float32 //数组保存语文和数学的考试成绩
TopPtr *int //int类型的指针,用于排名
SliceIndex []int //int类型的切片,定义学生各项指数,使用的时候需要make
Other map[string]string //定义一个map用于保存其它额外信息,使用的时候需要make
}
func main() {
var top = 21 //班级排名
var marley miniStudent
marley.stu.Name = "张三" //从Student继承的字段(属性)
marley.stu.Address = "北京-海淀区-中关村-清华大学-门口保安室" //从Student继承并显式声明
marley.stu.StuNum = "202001006" //从Student继承,隐匿声明,由编译器自动补全
marley.Age = 10 //年龄
marley.Scores = [2]float32{89.5, 95} //语文、数学的成绩
marley.TopPtr = &top //将排名的内存地址传给TopPtr
marley.SliceIndex = []int{10, 20, 30, 40} //切片可以自动make,也可以手动先make再使用
marley.Other = map[string]string{"father": "张大牛", "mather": "李金花"} //map可以自动make,也可以手动先make再使用
fmt.Println(marley) //{{张三 202001006 北京-海淀区-中关村-清华大学-门口保安室} 10 [89.5 95] 0xc00002c008 [10 20 30 40] map[father:张大牛 mather:李金花]}
}
运行结果:
{{张三 202001006 北京-海淀区-中关村-清华大学-门口保安室} 10 [89.5 95] 0xc00008c098 [10 20 30 40] map[father:张大牛 mather:李金花]}
结构体创建实体的更多方式集合:
使用工厂模式实现构造方法:
package main
import "fmt"
type student struct {
Name string
Age int
}
// 把要初始化的参数放入到NewStudent这个函数里面,然后返回一个*student的指针里面
func NewStudent(n string, a int) *student {
return &student{
Name: n,
Age: a,
}
}
// 给student绑定一个私有方法
func (s student) info() {
fmt.Println(s.Name, "的年龄是", s.Age) //打印出对象的信息
}
// 绑定私有方法,可修改名字和年龄
func (s *student) changeName(n string, a int) {
*s = student{n, a} //这是标准写法,*s可以简写为s
}
func main() {
var stu = NewStudent("张三", 10)
fmt.Println(stu)
fmt.Println(*stu)
fmt.Println("stu的类型是:%Tn", stu)
stu.info()
stu.changeName("李四", 18)
stu.info()
}
运行结果:
&{张三 10}
{张三 10}
stu的类型是:%Tn &{张三 10}
张三 的年龄是 10
李四 的年龄是 18
使用 new
func main() {
xm := new(Profile)
// 等价于: var xm *Profile = new(Profile)
fmt.Println(xm)
// output: &{ 0 }
xm.name = "iswbm" // 或者 (*xm).name = "iswbm"
xm.age = 18 // 或者 (*xm).age = 18
xm.gender = "male" // 或者 (*xm).gender = "male"
fmt.Println(xm)
//output: &{iswbm 18 male}
原文地址:https://blog.csdn.net/2302_79993788/article/details/143380322
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!