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())

}

 

posted @ 2021-04-09 14:19  fly_fly_fly#  阅读(73)  评论(0编辑  收藏  举报