go语言面向对象 | 青训营笔记

70 阅读4分钟

go语言面向对象 | 青训营笔记

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

1.面向对象结构体

面向对象需要设置结构体,即面向对象中的类,定义格式类似为c语言的结构体;然后单独写其实现方法,定义方法时需要加参数this 类名来确定为此类的方法。类名、属性名、⽅法名 ⾸字⺟⼤写表示对外(其他包) 可以访问,否则只能够在本包内访问。

type Hero struct {
	Name  string
	Ad    int
	Level int
}
func (this Hero) Show() {
	fmt.Println(this)
}
func (this Hero) GetName() {
	fmt.Println("Name=", this.Name)
}

2.值传递和引用传递

如果在this传参数中按以上代码来实现,则只能进行值传递,不能更改此类的实际数据,需要加*,指针类型变量。一个方法的接收者是指针类型,一个方法的接收者是值类型。

package main


import "fmt"


//定义一个结构体
type T struct {
    name string
}


func (t T) method1() {
    t.name = "new name1"
}


func (t *T) method2() {
    t.name = "new name2"
}


func main() {


    t := T{"old name"}


    fmt.Println("method1 调用前 ", t.name)
    t.method1()
    fmt.Println("method1 调用后 ", t.name)


    fmt.Println("method2 调用前 ", t.name)
    t.method2()
    fmt.Println("method2 调用后 ", t.name)

3.继承

跟其他语言一样,先定义父类的结构体和其方法,然后定义子类的时候,需要在结构体声明一下父类,子类中可以重新定义父类的方法,也可以继续添加新的方法。当给子类赋值时有两种赋值方法,1为在定义赋值时需要在大括号中添加子类的属性;2为直接声明一个类名,然后分别添加其属性值

type Human struct {
	name string
	sex  string
}

func (this *Human) Eat() {
	fmt.Println("Human.Eat().....")
}
func (this *Human) Walk() {
	fmt.Println("Human.Walk().....")
}

type SuperMan struct {
	Human //SuperMan类继承了Human类的方法
	level int
}

//重定义父类的方法Eat()
func (this *SuperMan) Eat() {
	fmt.Println("SuperMan.Eat().....")
}

//子类的新方法
func (this *SuperMan) Fly() {
	fmt.Println("SuperMan.Fly()...")
}
func main() {
	h := Human{"zhangsan", "female"}
	h.Eat()
	h.Walk()
	//定义一个子类对象
	//第一种赋值方法
	//s := SuperMan{Human{"li4", "female"}, 88}
	//第二种赋值方法
	var s SuperMan
	s.name = "li4"
	s.sex = "female"
	s.level = 88
	s.Walk() //父类的方法
	s.Eat()  //子类的方法
	s.Fly()  //子类的方法


4.多态

多态即指将一个对象变量引用多种实际类型,多态需要有三种必要条件:

  • 有若干子类继承同一个父类;
  • 子类重写了父类中的方法;
  • 父类的引用指向了子类对象

同一个类型的对象执行同一个行为,会表现出不同的行为特征。又由于多态更加侧重于行为多态,因此变量的调用和方法调用是不同的。在实现时可以使用通用数据类型interface类型,该类型为指针型变量,定义结构体父类需要定义其属性和定义其方法,实现了父类全部接口的方法的类是子类,具体定义时,使用了父类的类型变量,声明数据,然后在使用子类的类名来进行传参,该父类调用方法时就显示多态性。

package main

import (
	"fmt"
)

// interface本质是一个指针
type AnimalIf interface {
	Sleep()
	GetColor() string //获取动物的颜色
	GetType() string  //获取动物的种类
}

// 具体的类
type Cat struct {
	color string
}

// 一个类重写了所有接口方法,表示一个具体的类
func (this *Cat) Sleep() {
	fmt.Println("Cat is Sleep")
}
func (this *Cat) GetColor() string {
	return this.color
}
func (this *Cat) GetType() string {
	return "Cat"
}

type Dog struct {
	color string
}

func (this *Dog) Sleep() {
	fmt.Println("DOg is Sleep")
}
func (this *Dog) GetColor() string {
	return this.color
}
func (this *Dog) GetType() string {
	return "Dog"
}
func main() {
	var animal AnimalIf //接口的数据类型,父类指针
	animal = &Cat{"green"}
	animal.Sleep() //调用的就是cat的sleep方法
	animal = &Dog{"yellow"}
	animal.Sleep() //调用的dog的sleep方法 多态表现
}

5.interface和断言机制

Golang的语言中提供了断言的功能。golang中的所有程序都实现了interface{}的接口,这意味着,所有的类型如string,int,int64甚至是自定义的struct类型都就此拥有了interface{}的接口,这种做法和java中的Object类型比较类似。那么在一个数据通过func funcName(interface{})的方式传进来的时候,也就意味着这个参数被自动的转为interface{}的类型。

类型断言有以下几种形式:

  • 直接断言使用:
var a interface{}

fmt.Println("Where are you,Jonny?", a.(string))

但是如果断言失败一般会导致panic的发生。所以为了防止panic的发生,我们需要在断言前进行一定的判断,如果断言失败,那么ok的值将会是false,但是如果断言成功ok的值将会是true,同时value将会得到所期待的正确的值。

  • 配合switch使用