Go语言快速上手 - 基础语言(3)|青训营

73 阅读4分钟

引言

又经过好多天的磨练,加深了基础,这次来讲讲封装

面向对象的特征

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

引申阅读:studygolang.com/articles/26…