Go后端开发 – 面向对象特征:结构体 && 继承 && 多态 && interface
文章目录
- Go后端开发 -- 面向对象特征:结构体 && 继承 && 多态 && interface
- 一、Go的结构体
- 1.结构体的声明和定义
- 2.结构体传参
- 二、将结构体变成类
- 1.向结构体中添加成员函数
- 2.结构体定义的访问权限问题
- 三、Golang面向对象的继承
- 四、interface接口与多态
- 1.由interface实现多态
- 2.通用万能类型
- 3.类型断言
一、Go的结构体
1.结构体的声明和定义
type
用来声明数据类型
//声明一种新的数据类型myint,是int的一个别名
type myint int
- 使用
type
定义结构体 - 对于结构体对象:
可以先定义后初始化;
也可以直接在{}中初始化
package main
import "fmt"
// 定义一个结构体
type Book struct {
title string
author string
}
func main() {
//可以先定义后初始化
var book1 Book
book1.title = "Golang"
book1.author = "李四"
//也可以直接在{}中初始化
book2 := Book{title: "c++", author: "王五"}
fmt.Println(book1)
fmt.Println(book2)
}
2.结构体传参
- 值传参
传递的是结构体的拷贝,原结构体不会发生改变
package main
import "fmt"
// 定义一个结构体
type Book struct {
title string
author string
}
func main() {
var book1 Book
book1.title = "Golang"
book1.author = "李四"
fmt.Println(book1)
changeBook(book1)
fmt.Println(book1)
}
func changeBook(book Book) {
book.author = "张三"
}
- 引用传递
传递的是结构体的指针,原结构体的值会改变
package main
import "fmt"
// 定义一个结构体
type Book struct {
title string
author string
}
func main() {
var book1 Book
book1.title = "Golang"
book1.author = "李四"
fmt.Println(book1)
changeBook(&book1)
fmt.Println(book1)
}
func changeBook(book *Book) {
book.author = "张三"
}
二、将结构体变成类
1.向结构体中添加成员函数
type Hero struct {
Name string
Ad int
Level int
}
func (this Hero) GetName() string {
return this.Name
}
GetName
这个函数前面的(this Hero)
表明这个函数是绑定于Hero
这个结构体中的成员函数,可以通过this
这个参数调用结构体中的成员
package main
import "fmt"
type Hero struct {
Name string
Ad int
Level int
}
func (hero Hero) GetName() string {
return hero.Name
}
func (hero Hero) SetName(newName string) {
hero.Name = newName
}
func main() {
hero1 := Hero{Name: "zhangsan", Ad: 25, Level: 3}
fmt.Println(hero1)
name1 := hero1.GetName()
fmt.Println(name1)
hero1.SetName("超人")
fmt.Println(hero1)
}
可以看到getName
可以获取结构体对象中的成员变量,但是setName
函数没有改变对象中的值
- 因为
hero
这个参数是调用该方法的对象的一个拷贝
- 将所有的
hero
参数都改为*Hero
类型,那么hero
参数就是调用该方法的对象的指针了,指向该对象的地址空间,能够改变对象的成员变量的值 - 因此对所有的成员函数,该参数都应该定义为指针类型的参数
package main
import "fmt"
type Hero struct {
Name string
Ad int
Level int
}
func (hero *Hero) GetName() string {
return hero.Name
}
func (hero *Hero) SetName(newName string) {
hero.Name = newName
}
func main() {
hero1 := Hero{Name: "zhangsan", Ad: 25, Level: 3}
fmt.Println(hero1)
name1 := hero1.GetName()
fmt.Println(name1)
hero1.SetName("超人")
fmt.Println(hero1)
}
2.结构体定义的访问权限问题
上面实例的结构体类型Hero
的首字母是大写的
go语言的封装是针对包来封装的,类的公有和私有都是针对包来的
-
类名首字母大写,代表其他包可以访问该类,可以定义该类对象
-
类的属性首字母大写,表示该属性是对外能够访问的(public),否则只能类的内部访问(private)
三、Golang面向对象的继承
go中的面向对象的继承没有公有、私有继承,只有一种类型的继承
实例:
package main
import "fmt"
type Human struct {
name string
sex string
}
func (human *Human) Eat() {
fmt.Println("Human.Eat()...")
}
func (human *Human) Walk() {
fmt.Println("Human.Walk()...")
}
type Superman struct {
Human //表示Superman类继承了Human类的方法
level int
}
// 重定义父类方法
func (superman *Superman) Eat() {
fmt.Println("Superman.Eat()...")
}
// 定义子类的新方法
func (superman *Superman) Fly() {
fmt.Println("Superman.Fly()...")
}
func main() {
h1 := Human{name: "zhangsan", sex: "male"}
h1.Eat()
h1.Walk()
//定义一个子类对象
s1 := Superman{Human{"蝙蝠侠", "male"}, 3}
s1.Eat() //子类重写的成员函数
s1.Walk() //父类成员函数
s1.Fly() //子类独有成员函数
}
- 上述实例中,
Superman
继承了Human
类,也就是继承了父类的全部成员 - 子类可以对父类的成员函数进行重写,也可以调用父类的成员函数
- 子类可以直接访问父类的成员变量
四、interface接口与多态
1.由interface实现多态
Golang中的多态需要依赖interface
接口实现;
interface
类型,本质是一个父类指针,用于定义接口,底层是指针指向函数列表
type AnimalIF interface {
Sleep()
GetColor() string //获取动物颜色
GetType() string //获取动物类别
}
- 如果一个类实现了
interface
中的所有方法,就代表该类实现了当前的interface
接口,就可以实现多态,interface
类型的的指针就可以指向该类的对象了 - 若一个类没有完全重写
interface
中的所有方法,则interface指针无法指向该类
实例
package interface_go
import "fmt"
// 本质是一个父类指针,用于定义接口,底层是指针指向函数列表
type AnimalIF interface {
Sleep()
GetColor() string //获取动物颜色
GetType() string //获取动物类别
}
// 具体的类
type Cat struct {
//无需在子类中继承interface,只需要实现interface的方法,就可以实现多态
//这样就可以用interface的指针去指向Cat对象
color string //猫的颜色
}
// 重写interface接口中的方法
// Cat类重写了interface中的所有方法,就代表该类实现了当前的接口
// 若Cat类没有完全重写interface中的所有方法,则interface指针无法指向该类
func (c *Cat) Sleep() {
fmt.Println("Cat is sleep")
}
func (c *Cat) GetColor() string {
return c.color
}
func (c *Cat) GetType() string {
return "Cat"
}
type Dog struct {
color string
}
func (d *Dog) Sleep() {
fmt.Println("Dog is sleep")
}
func (d *Dog) GetColor() string {
return d.color
}
func (d *Dog) GetType() string {
return "Dog"
}
// 使用父类指针来接受子类对象
func showAnimal(animal AnimalIF) {
animal.Sleep()
fmt.Println("color = ", animal.GetColor())
fmt.Println("type = ", animal.GetType())
}
func Interface() {
var animal AnimalIF //接口的数据类型,也就是父类的指针
animal = &Cat{"yellow"} //通过匿名对象的指针给接口赋值,
animal.Sleep() //调用的就是Cat的Sleep()方法
animal = &Dog{"black"}
fmt.Println(animal.GetColor()) //调用的就是Dog的GetColor()方法,多态的现象
}
-
上述实例中,创建了名为AnimalIF的interface接口,包含三个方法
-
Cat和Dog类重写了AnimalIF的所有接口,因此AnimalIF指针可以指向Cat和Dog类的对象,进而实现多态
-
还可以通过AnimalIF类型的指针,接受Cat和Dog类对象的地址,这样也可以体现出多态
package interface_go
import "fmt"
// 本质是一个父类指针,用于定义接口,底层是指针指向函数列表
type AnimalIF interface {
Sleep()
GetColor() string //获取动物颜色
GetType() string //获取动物类别
}
// 具体的类
type Cat struct {
//无需在子类中继承interface,只需要实现interface的方法,就可以实现多态
//这样就可以用interface的指针去指向Cat对象
color string //猫的颜色
}
// 重写interface接口中的方法
// Cat类重写了interface中的所有方法,就代表该类实现了当前的接口
// 若Cat类没有完全重写interface中的所有方法,则interface指针无法指向该类
func (c *Cat) Sleep() {
fmt.Println("Cat is sleep")
}
func (c *Cat) GetColor() string {
return c.color
}
func (c *Cat) GetType() string {
return "Cat"
}
type Dog struct {
color string
}
func (d *Dog) Sleep() {
fmt.Println("Dog is sleep")
}
func (d *Dog) GetColor() string {
return d.color
}
func (d *Dog) GetType() string {
return "Dog"
}
// 使用父类指针来接受子类对象
func showAnimal(animal AnimalIF) {
animal.Sleep()
fmt.Println("color = ", animal.GetColor())
fmt.Println("type = ", animal.GetType())
}
func Interface() {
c1 := Cat{"yellow"}
d1 := Dog{"white"}
showAnimal(&c1)
showAnimal(&d1)
}
2.通用万能类型
interface{}
空接口:为Golang的万能类型,基本类型如int, string, float32, float64, struct等都实现了interface{}
(因为空接口中没有具体的接口),因此interface{}
这种类型的变量可以引用任意的数据类型
实例:
package interface_go
import "fmt"
// arg这个参数可以接受任意的类型
func allType(arg interface{}) {
fmt.Println(arg)
}
type Book struct {
name string
author string
}
func Interface() {
book1 := Book{"shijie", "zhangsan"}
allType(book1)
allType(120)
allType(12.5848)
}
- 在上述实例中,函数
allType
的参数arg
的类型是interface{}
,是通用万能类型,能够接受任意类型的参数
3.类型断言
Golang为interface{}
类型提供了类型断言,用于判断interface{}
类型变量引用的参数底层数据类型是什么
- 断言的格式为:
value, ok := arg.(string)
如果断言成功,即arg是string类型,则value被赋值为string类型的arg的值,ok被赋值为true;否则value为空,ok为false
实例:
package interface_go
import "fmt"
// arg这个参数可以接受任意的类型
func allType(arg interface{}) {
fmt.Println(arg)
//interface{}改如何区分 此时引用的底层数据类型到底是什么
value, ok := arg.(string)
if ok {
fmt.Println("arg is string type, value = ", value)
} else {
fmt.Println("arg is not string type")
}
}
type Book struct {
name string
author string
}
func Interface() {
book1 := Book{"shijie", "zhangsan"}
allType(book1)
allType(120)
allType(12.5848)
}
interface{}
断言可以配合switch语句使用,switch t := arg.(type) { }
是switch语句的独有断言方式,arg.(type)
不可脱离switch语句单独使用
package interface_go
import "fmt"
// arg这个参数可以接受任意的类型
func allType(arg interface{}) {
switch t := arg.(type) {
case string:
fmt.Println("arg is string type, value = ", t)
case int:
fmt.Println("arg is int type, value = ", t)
case float32:
fmt.Println("arg is float32 type, value = ", t)
case float64:
fmt.Println("arg is float64 type, value = ", t)
default:
fmt.Println("arg is unexpected type")
}
}
type Book struct {
name string
author string
}
func Interface() {
book1 := Book{"shijie", "zhangsan"}
allType(book1)
allType(120)
allType(12.5848)
}