引言
又经过好多天的磨练,加深了基础,这次来讲讲封装
面向对象的特征
struct(封装)
类名、属性名、方法名 首字母大写表示对外(其他包)可以访问,否则只能够在本包内访问
(1)struct基本定义与使用:
例:当利用type的时候,可以把某种自定义数据类型名称底层变成已经存在的类型:
type myint int
func main(){
var a myint = 10
fmt.Println("a =",a) //a = 10
fmt.Printf("type of a = %T\n",a) //type of a = main.myint
}
定义一个结构体:
type Book struct{
title string
auth string
}
在主函数中的使用:
func main(){
var book1 Book //将book1定义为Book的属性
book1.title = "Golang"
book1.auth = "zhang3"
fmt.Printf("%v\n", book1)
}
然后在其他函数中引用时,必须得利用指针才能有效改变其中的值
func changeValue(book Book){ //不改变外面book1的值,只是传递了一个book副本
book.auth = 666
}
func changeValue2(book *Book){ //会直接改变book1的值,指针传递
book.auth = 666
}
//在main中也得相应传递不同的东西
func main(){
var book1 Book
changeValue(book1)
changeValue2(&book1)//传递地址
}
(2)另一种表示
type Hero struct{ //注意:开头大写代表是公有类
Name string
Ad int
Level int
}
func (this *Hero) Show() {
fmt.Println("Name =", this.Name)
fmt.Println("Ad =", this.Ad)
fmt.Println("Level", this.Level)
}
func (this *Hero) SetName(newName string){ //一般用指针,不然无法改变真正的值
this.Name = newName
}
func main(){
//创建一个对象hero
hero := Hero{Name:"Zhang3",Ad:100,Level:1}
hero.Show()
hero.SetName("li4")
hero.Show()
}
继承
定义:
//父类
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
}
//定义子类的方法
func (this *SuperMan) Eat(){
fmt.Println("SuperMan.Eat()...")
}
func (this *SuperMan) Fly(){
fmt.Println("SuperMan.Fly()...")
}
定义好父类与子类后,在main中定义对象:
func main(){
//父类
var h Human
h.Name = "Zhang3"
h.Sex = "female"
h.Eat() //Human.Eat()...
h.Walk() //Human.Walk()...
//=================================
//子类
//s := SuperMan{Human{"li4","male"},1} 另外一种定义方式
var s SuperMan
s.Name = "li4"
s.Sex = "male"
s.Level = 1
s.Eat() //SuperMan.Eat()...
s.Fly() //SuperMan.Fly()...
s.Walk() //Human.Walk()... 从Human继承过来
}
多态(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()方法,多态的现象
}
这么写比较麻烦可以直接定义一个方法,更便捷的调用
func showAnimal(animal AnimalIF){ //直接将指针作为形参
animal.Sleep() //传什么对象调用什么对象的方法
fmt.Println("color =", animal.GetColor())
fmt.Println("kind =", animal.GetType())
}
func main(){
cat := Cat("Green")
dog := Dog("Yellow")
showAnimal(&cat) //Cat is Sleep...
showAnimal(&dog) //Dog is Sleep...
}
##### 通用万能类型
定义:空接口;int、string、float32、float64、struct...;实现interface{}后可以用interface{}类型引用任意的数据类型
//interface{}是万能数据类型
func myFunc(arg interface{}) {
fmt.Println("myFunc is called...")
fmt.Println(arg)
}
type Book struct {
auth string
}
func main(){
book := Book{"Golang"}
myFunc(book)
myFunc(100)
myFunc("abc")
myFunc(3.14)
...//都可以放入
}
类型断言机制:我们已经知道接口可以分为空接口与非空接口两类。相对于接口这种“抽象类型”,像int,slice,string,map,struct等类型被称为“具体类型”。类型断言是Go语言中应用在接口值上的一个神奇特性,而类型断言的目标类型可以是某种具体类型,也可以是某种非空接口类型。
类型断言 type assertion,和上节的类型转换不同,类型断言是将接口类型的值x,转换成类型T。格式为:
x.(T) v := x.(T) v, ok := x.(T)
类型断言的必要条件是x是接口类型,非接口类型的x不能做类型断言
var i int = 10
v := i.(int) //错误
T可以是非接口类型,如果想断言合法,则T应该实现x的接口。
T也可以是接口,则x的动态类型也应该实现接口T。
var x interface{} = 7 // x 的动态类型为int, 值为 7 i := x.(int) // i 的类型为 int, 值为 7 type I interface { m() } var y I s := y.(string) // 非法: string 没有实现接口 I (missing method m) r := y.(io.Reader) // y如果实现了接口io.Reader和I的情况下, r的类型则为io.Reader
b站例子:
func myFunc(arg interface{}) {
fmt.Println("myFunc is called...")
fmt.Println(arg)
//interface{}该如何区分,此时引用的底层数据类型到底是什么?
//给interface{} 提供“类型断言”的机制
value, ok := arg.(string)
if !ok{
fmt.Println("arg is not string type")
}else{
fmt.Println("arg is string type, value =",value)
fmt.Printf("value type is %T\n", value)
}
}