go面向对象1
类的定义
借助结构体实现 关键字 type
type Student struct {
id uint
name string
male bool
score float64
}
go 没有构造函数 析构函数 取而代之的是 NewXxx这样的全局函数(首字母大写) 作为类的初始化函数
func NewStudent(id uint,name string,male bool,score float64) *Student {
return &Student{id,name,male,score}
}
通过传入属性字段对Student类进行初始化并返回一个指向该类的指针
还可以初始化指定字段
func NewStudent(id uint,name string,socre float64) *Student{
return &Student{id:id,name:name,score:score}
}
然后在main()主函数中调用NewStudent函数对Student类进行初始化
func main(){
studnet := NewStudent(1,"fly",90.1)
fmt.Println(student)
}
//结果 &{1 fly false 90.1}
为类添加成员方法
在func和方法名之间添加方法所属的类型声明
func (s Student) GetName() string {
return s.name
}
student := NewStudent(1,"fly",10)
fmt.Println("name",student.GetName())
设置name值的方法
func (s *Student) SetName(name string){
s.name = name
}
这个和前面 getName方法不一样 Student设置成了指针类型 s *Studnet
go所有的东西都是显式声明
在 GetXXX
方法中,由于不需要对类的成员变量进行修改,
所以不需要传入指针,而 SetXXX
方法需要在函数内部修改成员变量的值,
并且作用到该函数作用域以外,所以需要传入指针类型(结构体是值类型,不是引用类型,所以需要显式传入指针)
指针方法 值方法
go语言中 当我们将成员方法 SetName 所属的类型声明为指针类型时, 严格来说 该方法并不属于Student 类 而是属于指向 Student 的指针类型 so 归属于 Student 的成员方法只是 Student
类型下所有可用成员方法的子集 归属于*Student 的成员方法才是Student类 完整可用方法的集合
我们在调用方法时 之所以可以直接在student 实例上调用SetName 方法 是因为go语言底层会自动将student 转化为对应的指针类型 &student 所真正调用的代码是 &student.SetName('fly')
总结: 自定义数据类型的方法集合中仅会包含他的所有【值方法】 而该类型对应的指针类型包含的方法集合才囊括该类型的所有方法 包括所有的 值方法 和 指针方法 指针方法可以修改所属类型的属性值
而值方法不能
go toString 方法实现
方法名 String
func (s Student) String() string {
return fmt.Sprintf("id:%d,name:%s,male:%t,score: %f",s.id,s.name,s.male,s.score)
}
main方法中调用
student := NewStudent(1,"fly",100)
fmt.Println(student)
//结果 {id:1,name:fly, male:false,score:100.000000}
二 ,通过组合实现类的继承和方法重写
面向对象的三大特征 封装 继承 多态
继承:go里面是通过组合的方式来实现
将一个类型嵌入到另外一个类型 从而构建新的类型结构
例子
type Animal struct {
Name string
}
func (a Animal) call() sting {
return "动物的叫声。。。"
}
func (a Animal) FavorFood() string {
return "爱吃的食物。。。"
}
func (a Animal) GetName() string{
return a.name
}
继承该类 的子类
type Dog struct{
Animal
}
这样 我们可以在dog实例上访问所有animal 类型包含的属性和方法
func main(){
animal = Animal{"中华田园犬"}
dog := Dog{animal}
fmt.Println(dog.GetName())
fmt.Println(dog.Call())
}
多态
方法重写
func (d Dog) FavorFood() string {
return "骨头"
}
func (d Dog) call() string {
return "汪汪汪"
}
还可以继续调用父类Animal中的方法
fmt.Println(dog.Animal.Call())
fmt.Println(dog.Call())
多继承同名方法冲突处理
组合的不能类型之间包含同名方法 比如Animal 和 Pet 都包含了 GetName方法 如果子类 Dog 没有重写该方法,直接在Dog实例调用会报错
type Pet struct {
Name string
}
func (p Pet)GetName string{
return p.Name
}
type Dog struct {
Animal
Pet
}
func main(){
animal := Animal{"泰迪"}
pet := Pet{"宠物狗"}
dog := Dog{animal,pet}
fmt.Println(dog.GetName)//报错
}
除非显示调用哪个父类的方法
fmt.Println(dog.Pet.GetName())
还可以调整组合位置改变内存布局
type Dog struct{
Animal
Pet
}
和
type Dog struct{
Pet
Animal
}
内存结构不一样
继承指针类型的属性和方法
type Dog struct{
*Animal
}
传入的animal要传入指针引用 ,例子
func main(){
animal := Animal{"中华田园犬"}
pet := Pet{"宠物狗"}
dog := Dog{&animal,pet}
}
为组合类型设置别名
type Dog struct{
animal *Animal
pet Pet
}
func main(){
animal := Animal{"中华田园犬"}
pet := Pet{"宠物狗"}
dog := Dog{&animal,pet}
//通过animal 引用 Animal 类型实例
fmt.Println(dog.animal.GetName())
}