局域网建设网站视频教程,网站优化怎样提高网站用户体验,有哪些做特卖的网站,哪家网站建设比较好go貌似都没有听说过继承#xff0c;当然这个继承不像c中通过class类的方式去继承#xff0c;还是通过struct的方式#xff0c;所以go严格来说不是面向对象编程的语言#xff0c;c和java才是#xff0c;不过还是可以基于自身的一些的特性实现面向对象的功能#xff0c;面向…go貌似都没有听说过继承当然这个继承不像c中通过class类的方式去继承还是通过struct的方式所以go严格来说不是面向对象编程的语言c和java才是不过还是可以基于自身的一些的特性实现面向对象的功能面向对象三大特性封装、继承、多态
封装
属性
go是接住结构体struct实现类的声明,比如要定义个学生类学生类和animal类是面向对象示例介绍中重点可以通过如下方式实现
type Student struct {id uintname stringmale boolscore float64
}结构体名或者说类名为 Student并且包含了 id、name、male、score 四个属性Go 语言中也不支持构造函数、析构函数取而代之地可以通过定义形如 NewXXX 这样的全局函数首字母大写作为类的初始化函数
func NewStudent(id uint, name string, male bool, score float64) *Student {return Student{id, name, male, score}
}在这个函数中我们通过传入的属性字段对 Student 类进行初始化并返回一个指向该类的指针
在 Go 语言中未进行显式初始化的变量都会被初始化为该类型的零值例如 bool 类型的零值为 falseint 类型的零值为 0string 类型的零值为空字符串float 类型的零值为 0.0。接着就可以调用了
package main
import (fmtstudent2 student/stu
)
func main() {student : student2.NewStudent(1, zhiyu,false, 100)fmt.Println(student)
}成员函数
getXXX方法
要为 Go 类定义成员方法需要在 func 和方法名之间声明方法所属的类型有的地方将其称之为接收者声明以 Student 类为例要为其定义获取 name 值的方法可以这么做
func (s Student) GetName() string {return s.name
}这样就可以使用GetName方法获取name属性通过在函数签名中增加接收者声明的方式定义了函数所归属的类型这个时候函数就不再是普通的函数而是类的成员方法了
setXXX方法
getName是一个只读方法setName是一个可写的方法所以需要使用指针的方式进行传参在类的成员方法中可以通过声明的类型变量来访问类的属性和其他方法
func (s *Student) SetName(name string) {s.name name
}可以把接收者类型为指针的成员方法叫做指针方法把接收者类型为非指针的成员方法叫做值方法二者的区别在于值方法传入的结构体变量是值类型类型本身为指针类型除外因此传入函数内部的是外部传入结构体实例的值拷贝修改不会作用到外部传入的结构体实例.
另外需要声明的是在 Go 语言中当我们将成员方法 SetName 所属的类型声明为指针类型时严格来说该方法并不属于 Student 类而是属于指向 Student 的指针类型所以归属于 Student 的成员方法只是 Student 类型下所有可用成员方法的子集归属于 *Student 的成员方法才是 Student 类完整可用方法的集合。
在调用值方法和指针方法时需要记住以下两条准则
值方法可以通过指针和值类型实例调用指针类型实例调用值方法时会自动解引用指针方法只能通过指针类型实例调用但有一个例外如果某个值是可寻址的或者说左值那么编译器会在值类型实例调用指针方法时自动插入取地址符使得在此情形下看起来像指针方法也可以通过值来调用
左值和右值
结合上面的两条准则使用示例说明如下
package mainimport fmt
type Student struct {id uintname stringscore float64
}func NewStudent(id uint, name string, score float64) *Student {return Student{id: id, name: name, score: score}
}func NewStudentV2(id uint, name string, score float64) Student {return Student{id: id, name: name, score: score}
}func (s Student) GetName() string {return s.name
}func (s *Student) SetName(name string) {s.name name
}func main() {s : NewStudent(1, zhiyu, 100)s.SetName(zhiyu-1) // ok 正常调用指针方法fmt.Println(s.GetName()) // ok 指针调用值方法自动解引用: (*s).GetName()s2 : NewStudentV2(2, zhiyu, 90)s2.SetName(zhiyu-2) // ok s2 是可寻址的左值所以实际调用: (s2).SetName(zhiyu-2)fmt.Println(s2.GetName()) // ok 正常调用值方法NewStudent(3, zhiyu, 80).SetName(zhiyu-3) // ok 正常调用指针方法NewStudentV2(4, zhiyu, 99).SetName(zhiyu-4) // err 值类型调用指针方法
}
之所以可以直接在 s2 值实例上调用 SetName 指针方法是因为 s2 是可寻址的Go 语言底层会自动将 s2 转化为对应的指针类型 s2所以真正调用的代码是 (s2).SetName(zhiyu-2)而通过 NewStudentV2(…)返回实例调用 SetName 时则会报错因为 NewStudentV2(…) 是一个不可以寻址的右值。
所谓左值就是可以出现在赋值等号左边的值而右值只能出现在赋值等号右边比如函数返回值、字面量、常量值等。左值可寻址右值不可寻址。
总结下来就是一个自定义数据类型的方法集合中仅会包含它的所有「值方法」而该类型对应的指针类型包含的方法集合才囊括了该类型的所有方法包括所有「值方法」和「指针方法」指针方法可以修改所属类型的属性值而值方法则不能。
值方法|指针方法
有如下情形的考量时需要将类方法定义为指针方法
数据一致性方法需要修改传入的类型实例本身方法执行效率如果是值方法在方法调用时一定会产生值拷贝而大对象拷贝代价很大。
通常我们都会选择定义指针方法
继承
Go 虽然没有直接提供继承相关的语法实现但是通过组合的方式间接实现类似功能所谓组合就是将一个类型嵌入到另一个类型从而构建新的类型结构。使用了Student类介绍封装接着使用Animal示例继承
package anitype Animal struct {Name string
}func (a Animal) Call() string {return 动物叫声
}func (a Animal) FavorFood() string {return 爱吃的食物...
}func (a Animal) GetName() string {return a.Name
}
所有的动物都有以上的三种方法现在Dog实现继承Animal新增一个dog.go一般会给自家的爱狗起一个别名
package anitype Dog struct {AnimalAlias string
}func (d Dog) GetAliasName() string {return d.Alias
}main.go中如下所示
package mainimport (animal/anifmt
)func main() {animal : ani.Animal{旺财}dog : ani.Dog{animal, 旺旺}fmt.Println(dog.GetName())fmt.Println(dog.Call())fmt.Println(dog.GetAliasName())
}这就实现了继承的功能。注意在初始化子类时的顺序和struct中的定义顺序是一致的
多态
所谓多态就是一个函数的多种形态比如在子类中定义同名函数来覆盖父类方法专业属于称之为方法重写。每个动物的喜欢吃的食物和叫声不同这里实现下Dog重写方法在dog.go中
package anitype Dog struct {AnimalAlias string
}func (d Dog) GetAliasName() string {return d.Alias
}func (d Dog) FavorFood() string {return 大棒骨
}func (d Dog) Call() string {return 旺旺
}重写go build并在terminal中在animal根目录下 当然子类也可以直接调用父类Animal中的方法
fmt.Print(dog.Animal.Call())
fmt.Println(dog.Call())
fmt.Print(dog.Animal.FavorFood())
fmt.Println(dog.FavorFood())