zoukankan      html  css  js  c++  java
  • 面向对象编程三大特征7

    多态及体现:

    基本介绍:

      变量(实例)具有多种形态。面向对象的第三大特征,在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。


    快速入门:

    在前面的Usb接口案例, Usb usb,既可以接收手机变量,又可以接收相机变量,就体现了Usb 接口多态特征。

    //编写一个方法Working 这个方法接收Usb接口类型的变量
    //只要是实现了 Usb接口 (所谓实现Usb接口就是指实现了Usb接口声明的所有方法)
    func (c Computer) Working(usb Usb) {   //usb 变量会根据传入的实参,来判断到底是Phone,还是Camera,usb 接口变量就体现出多态的特点。
      //通过usb接口变量来调用Start和Stop方法
      usb.Start()
      usb.Stop()
    }

    接口体现多态特征:

    1)多态参数

      在前面的Usb接口案例,usb Usb,既可以接收手机变量,又可以接收相机变量,就体现了Usb 接口多态特征。

    2)多态数组

      演示一个案例:给Usb数组中,存放Phone 结构体 和 Camera 结构体变量,Phone还有一个特有的方法call(),请遍历Usb数组,如果是Phone变量,除了调用Usb 接口声明的方法外,还需要调用Phone 特有方法 call。

    蓝色部分讲完类型断言之后再讲特有的调用方法。

    案例说明:

    //声明一个接口
    type Usb interface {
      //声明了两个没有实现的方法
      Start()
      Stop()
    }

    type Phone struct {
      name string
    }

    //让Phone 实现 Usb接口的方法
    func (p Phone) Start() {
      fmt.Println("手机开始工作...")
    }

    func (p Phone) Stop() {
      fmt.Println("手机停止工作...")
    }

    type Camera struct {
      name string
    }

    //让camera 实现了Usb接口的方法
    func (c Camera) Start() {
      fmt.Println("相机开始工作...")
    }

    func (c Camera) Stop() {
      fmt.Println("相机停止工作...")
    }

    func main() {

      //定义一个usb接口数组,可以存放Phone和Camera结构体变量
      //这里就体现多态数组
      var usbArr [3]Usb
      usbArr[0] = Phone{"vivo"}
      usbArr[1] = Phone{"小米"}
      usbArr[2] = Camera{"三星"}
      fmt.Println(usbArr)
    }

    类型断言:

    先看一个需求:

    看一段代码
    type Point struct {
      x int
      y int
    }

    func main() {
      var a interface{}
      var point Point = Point{1,2}
      a = point   //ok
      //如何将a赋给一个Point变量?
      var b Point
      b = a   //可以吗? ==>error 必须是 b = a.(Point) 类型断言
      fmt.Println(b)
    }

    b = a.(Point) 就是类型断言,表示判断a是否指向Point类型的变量,如果是就转成Point类型并赋给b变量,否则报错。

    需求:如何将一个接口变量,赋给自定义类型的变量. => 引出类型断言


    基本介绍:

    类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言,具体的如下:


    案例:

    func main() {
      var x interface {}
      var b float32 = 1.1
      x = b //空接口,可以接收任意的类型
      // x=>float32 [使用类型断言]
      y := x.(float32)
      fmt.Printf("y 的类型是 %T 值是%v", y, y)
    }


    对上面的代码说明:

    在进行类型断言时,如果类型不匹配,就会报 panic,因此进行类型断言时,要确保原来的空接口指向的就是断言的类型。

    比如 y := x.(float32) 写成float64就不行了,因为空接口指向的是float32类型。


    如何在进行断言时,带上检测机制,如果成功就OK,否则也不需要报 panic。

    带检测的类型断言:

    func main() {
      var x interface {}
      var b float32 = 2.1
      x = b //空接口,可以接收任意的类型
      // x=>float32 [使用类型断言]

      //类型断言(带检测的)
      //y, flag := x.(float32)
      if y, flag := x.(float32); flag {
        fmt.Println("convert success")
        fmt.Printf("y 的类型是 %T 值是%v", y, y)
      } else {
        fmt.Println("convert fail")
      }
      fmt.Println("继续执行~~~")
    }


    类型断言的最佳实践1:

    在前面的Usb接口案例做改进:

      给Phone 结构体增加一个特有的方法call(),当Usb 接口接收的是Phone 变量时,还需要调用call方法。

    //声明一个接口
    type Usb interface {
      //声明了两个没有实现的方法
      Start()
      Stop()
    }

    type Phone struct {
      name string
    }

    //让Phone 实现 Usb接口的方法
    func (p Phone) Start() {
      fmt.Println("手机开始工作...")
    }

    func (p Phone) Stop() {
      fmt.Println("手机停止工作...")
    }

    func (p Phone) Call() {
      fmt.Println("手机 在打电话..")
    }

    type Camera struct {
      name string
    }

    //让camera 实现了Usb接口的方法
    func (c Camera) Start() {
      fmt.Println("相机开始工作...")
    }

    func (c Camera) Stop() {
      fmt.Println("相机停止工作...")
    }

    type Computer struct {

    }

    func (computer Computer) Working(usb Usb) {
      usb.Start()
      //如果usb是指向Phone结构体变量,则还需要调用Call方法。
      //类型断言...[注意体会!!!]
      if a, ok := usb.(Phone); ok {
        a.Call()
      }
      usb.Stop()
    }

    func main() {

      //定义一个usb接口数组,可以存放Phone和Camera结构体变量
      //这里就体现多态数组
      var usbArr [3]Usb
      usbArr[0] = Phone{"vivo"}
      usbArr[1] = Phone{"小米"}
      usbArr[2] = Camera{"三星"}

      //遍历usbArr
      var computer Computer
      for _, v := range usbArr{
        computer.Working(v)
        fmt.Println()
      }
      fmt.Println(usbArr)
    }


    类型断言的最佳实践2:

    //编写一个函数,可以判断输入的参数是什么类型
    func TypeJudge(items... interface{}) {    //表示这个函数可以接收多个的任意类型的实参
      for i, x := range items {
        switch x.(type) { //这里type是一个关键字,固定写法
          case bool:
            fmt.Printf("第%d个参数是 bool 类型,值是%v ", i+1, x)
          case float32:
            fmt.Printf("第%d个参数是 float32 类型,值是%v ", i+1, x)
          case float64:
            fmt.Printf("第%d个参数是 float64 类型,值是%v ", i+1, x)
          case int, int32, int64:
            fmt.Printf("第%d个参数是 整数 类型,值是%v ", i+1, x)
          case string:
            fmt.Printf("第%d个参数是 string 类型,值是%v ", i+1, x)
          default:
            fmt.Printf("第%d个参数是 类型 不确定,值是%v ", i+1, x)
        }
      }
    }

    func main() {

      var n1 float32 = 1.1
      var n2 float64 = 2.3
      var n3 int64 = 30
      var name string = "tom"
      address := "北京"
      n4 := 300

      TypeJudge(n1, n2, n3, name, address, n4)
    }

    结果是:

    类型断言的最佳实践3:

    在前面代码的基础上,增加判断Student 类型和 *Student类型

    package main
    import (
      "fmt"

    )

    type Student struct {

    }

    //编写一个函数,可以判断输入的参数是什么类型
    func TypeJudge(items... interface{}) {
      for i, x := range items {
        switch x.(type) { //这里type是一个关键字,固定写法
          case bool:
            fmt.Printf("第%d个参数是 bool 类型,值是%v ", i+1, x)
          case float32:
            fmt.Printf("第%d个参数是 float32 类型,值是%v ", i+1, x)
          case float64:
            fmt.Printf("第%d个参数是 float64 类型,值是%v ", i+1, x)
          case int, int32, int64:
            fmt.Printf("第%d个参数是 整数 类型,值是%v ", i+1, x)
          case string:
            fmt.Printf("第%d个参数是 string 类型,值是%v ", i+1, x)
          case Student :
            fmt.Printf("第%d个参数是 Student 类型,值是%v ", i+1, x)
          case *Student :
            fmt.Printf("第%d个参数是 *Student 类型,值是%v ", i+1, x)
          default:
            fmt.Printf("第%d个参数是 类型 不确定,值是%v ", i+1, x)
        }
      }
    }

    func main() {

      var n1 float32 = 1.1
      var n2 float64 = 2.3
      var n3 int64 = 30
      var name string = "tom"
      address := "北京"
      n4 := 300

      stu1 := Student{}
      stu2 := &Student{}

      TypeJudge(n1, n2, n3, name, address, n4, stu1, stu2)
    }

  • 相关阅读:
    ld: cannot find lgcc_s
    Ubuntu 12.10 图形显示未知
    awk分析Nginx日志中的cookie
    Ubuntu 10.04 WPS 问题汇总
    objc[20556]:Class JavaLaunchHelper is implemented in both xxx 警告处理
    在Linux安装配置Tomcat 并部署web应用 ( 三种方式 )
    Spring Boot 系列(二)单元测试&网络请求
    Java自定义注解
    Spring Boot 系列(一)快速入门
    Spring 自定义注解,配置简单日志注解
  • 原文地址:https://www.cnblogs.com/green-frog-2019/p/11415543.html
Copyright © 2011-2022 走看看