Go语言之接口

接口就是一系列方法的集合(规范行为)

在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为,规范子类对象的行为。

在 Go 语言中的接口是非侵入式接口(接口没了,不影响代码),侵入式接口(接口没了,子类报错)

Go 也是鸭子类型,比如我现在有个鸭子类,内有 speak 方法和 run 方法,子类只要实现了 speak 和 run,我就认为子类是鸭子,我只要子类中有这两个方法你就是鸭子,有这两个方法你就是鸭子,他是从下往上推导只要有你这里面的东西,那就是算是继承了你这个接口

1、接口的用途

接口是一个类型

// Duck 定义一个鸭子接口
type Duck interface {
   speak()
   run()
}

// WhiteDuck 定义一个白鸭子结构体
type WhiteDuck struct {
   name  string
   age int
   sex string
}

// BlackDuck 定义一个黑鸭子结构体
type BlackDuck struct {
   name  string
   age int
   sex string
}

// 让白鸭子和黑鸭子绑定接口中的所有方法,就叫实现该接口
// 让白鸭子实现 Duck 接口
func (w WhiteDuck) speak() {
   fmt.Println("白鸭子嘎嘎叫,它的名字叫", w.name)
}

func (w WhiteDuck) run() {
   fmt.Println("白鸭子慢悠悠的走,它的名字叫", w.name)
}

// 让黑鸭子实现 Duck 接口
func (b BlackDuck) speak() {
   fmt.Println("黑鸭子呱呱叫,它的名字叫", b.name)
}

func (b BlackDuck) run() {
   fmt.Println("黑鸭子歪歪扭扭的走,它的名字叫", b.name)
}

func main() {
   var duck Duck
   duck = WhiteDuck{"小白", 15, "男"}  // 把我的对象赋值给一个接口类型,就可以实现多态的效果
   fmt.Println(duck)

   // duck 现在他是一个接口,它只能取方法,不能取出属性了。
   duck.speak()
   duck.run()
}

// 输出:
{小白 15 男}
白鸭子嘎嘎叫,它的名字叫 小白
白鸭子慢悠悠的走,它的名字叫 小白

2、类型断言

用于提取接口的底层值,就是把接口类型转成 struct ,属性,自有方法也有了。

func main() {
    var duck Duck = WhiteDuck{"小白", 15, "男"}
    // 断言是 WhiteDuck 类型
    value, ok := duck.(WhiteDuck)
    // 断言成功,ok=true,value就是WhiteDuck结构体对象
    fmt.Println(value)      // 输出:{小白 15 男}
    fmt.Println(value.name) // 输出:小白
    fmt.Println(ok)         // 输出:true

    // 断言失败,ok1=false,value1是BlackDuck类型的空值,因为没有赋值
    value1, ok1 := duck.(BlackDuck)
    fmt.Println(value1)     // 输出:{ 0 }
    fmt.Println(ok1)        // 输出:false
}

3、类型选择

(通过 Type Switch )

用于将接口的具体类型与很多 case 语句所指定的类型进行比较。

func main() {
   var duck Duck = WhiteDuck{"小白", 15, "男"}
   test(duck)
}

func test(duck Duck) {
   switch value := duck.(type) {
   case WhiteDuck:
      fmt.Println(value.name)
      fmt.Println("我是白鸭子")
   case BlackDuck:
      fmt.Println(value.name)
      fmt.Println("我是黑鸭子")
   default:
      fmt.Println(value)
      fmt.Println("我是鸭子这个类")
   }
}

4、空接口

没有任何方法,所有数据类型都实现了空接口

type Empty interface {} // 空接口

func main() {
   var a int = 10
   var b string = "XiaoYang"
   var c [3]int
   var e Empty    // e是空接口类型,可以接受任意的数据类型
   e = a
   e = b
   e = c

   // 这样的话需要把它类型选择回来
   // 正常情况下我只能接收 Empty 类型的,但是 a b c 都不是 Empty 类型的
   test(a)  // 输出:我是int 10
   test(b)  // 输出:我是字符串 XiaoYang
   test(c)  // 输出:我是数组 [0 0 0]
}

// 如果这不是一个空接口,比如是 Duck 那么只要实现了 Duck 接口的所有数据类型都可以传
func test(b Empty)  {
   switch v:=b.(type) {
   case string:
      fmt.Println("我是字符串", v)
   case int:
      fmt.Println("我是int", v)
   case [3]int:
      fmt.Println("我是数组", v)
   }
}

5、匿名空接口

没有名字的空接口,一般用在形参上

func main() {
   var duck Duck = WhiteDuck{"小白", 15, "男"}
   test(10)
   test("XiaoYang")
   test(duck)
}

// 这叫匿名空接口,所有数据类型都可以往里面传,如果想用原来的结构体还需要类型选择回来才能用
func test(b interface{}) {
   fmt.Println(b)
}

6、实现多个接口

// Duck 定义一个鸭子接口
type Duck interface {
   speak()
   run()
}

type Animal interface {
   eat()
   sleep()
}

// WhiteDuck 定义一个白鸭子结构体
type WhiteDuck struct {
   name string
   age  int
   sex  string
}

// 让白鸭子即实现 Duck 接口也实现了 Animal 接口
func (w WhiteDuck) speak() {
   fmt.Println("白鸭子嘎嘎叫,它的名字叫", w.name)
}

func (w WhiteDuck) run() {
   fmt.Println("白鸭子慢悠悠的走,它的名字叫", w.name)
}

func (w WhiteDuck) eat() {
   fmt.Println("白鸭子吃饭,它的名字叫", w.name)
}

func (w WhiteDuck) sleep() {
   fmt.Println("白鸭子睡觉,它的名字叫", w.name)
}

func main() {
    var w WhiteDuck = WhiteDuck{}
    var a Animal
    var d Duck

    // 这样的话我的 w 即可以给 a ,也可以给 d
    // 但是一旦转到某个接口上,只能使用该接口的方法,自身属性和自身方法需要类型断言后才能使用

    a = w       // w 给了 a ,那么 a 就只能调用 Animal 接口的方法
    a.sleep()
    a.eat()

    d = w       // w 给了 d ,那么 a 就只能调用 Duck 接口的方法
    d.run()
    d.speak()
}

7、接口嵌套

type Duck interface {
   Animal    // Duck 嵌套 Animal 接口
   speak()
   run()
}

type Animal interface {
   eat()
   sleep()
}

type WhiteDuck struct {
   name string
   age  int
   sex  string
}

// 这样白鸭子即实现 Duck 接口也实现了 Animal 接口
func (w WhiteDuck) speak() {
   fmt.Println("白鸭子嘎嘎叫,它的名字叫", w.name)
}

func (w WhiteDuck) run() {
   fmt.Println("白鸭子慢悠悠的走,它的名字叫", w.name)
}
func (w WhiteDuck) eat() {
   fmt.Println("白鸭子嘎嘎叫,它的名字叫", w.name)
}

func (w WhiteDuck) sleep() {
   fmt.Println("白鸭子慢悠悠的走,它的名字叫", w.name)
}

func main() {
   var a Animal
   var d Duck
   var w WhiteDuck = WhiteDuck{}

   // w 即可以给 a,也可以给 d
   a = w     // 但是 a 只能调用 Animal 中的两个方法
   a.sleep()
   a.eat()

   d = w     // d 却能调用 Duck 和 Animal 中的四个方法
   d.sleep()
   d.eat()
   d.speak()
   d.run()
}

8、接口零值

func main() {

   var a Animal   // nil 就是说明它是一个引用类型
   // 其内部表示就已经告诉了我们,它里面就存两个值,一个是它的类型,一个是指向具体值的指针

   fmt.Println(a) // 输出:
}

9、make和new的区别

type WhiteDuck struct {
   name string
   sex  string
   age  int
}

func main() {
   var per1 *WhiteDuck = new(WhiteDuck) // new 是返回指向这个类型的指针
   // 或者是我取 WhiteDuck 的地址,赋值给 per2
   var per2 = &WhiteDuck{}

   fmt.Println(per1)  // 输出:&{  0}
   fmt.Println(per2)  // 输出:&{  0}

   var per3 = make([]int, 3, 4)   // make 是具体的创建引用类型
                           // new 是创建指向这个类型的指针
   var per4 = new([]int)        // 是一个指向切片类型的指针

   fmt.Println(per3)  // 输出:[0 0 0]
   fmt.Println(per4)  // 输出:&[]
}

Original: https://www.cnblogs.com/XiaoYang-sir/p/15388749.html
Author: Mr-Yang`
Title: Go语言之接口

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516566/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • go-zero单体服务使用泛型简化注册Handler路由

    一、Golang环境安装及配置Go Module https://go-zero.dev/cn/docs/prepare/golang-install mac OS安装Go 下载并…

    Go语言 2023年5月25日
    072
  • HTTP 尝试获取 Client IP

    HTTP 中获取 Client IP 相关策略需求, 在当下网络环境中多数只能提供建议作用. 更多的是 通过其它唯一标识来挖掘更多潜在价值. 本文主要就一个内容, 如何最大可能尝试…

    Go语言 2023年5月25日
    058
  • 字符集与编码

    一个比特(bit)可以是0,或者是1,8个比特(bit),组成一个字节(byte)。全为0时代表数字0,全为1时代表数字255。 一个字节可以表示256个数字,两个字节可以表示65…

    Go语言 2023年5月25日
    049
  • 微服务-限流:一.golang实现令牌桶算法

    起初是因为要去拉取一些第三方的数据,而第三方的API接口都有限流措施。比如6000/分钟,500/分钟。想着拉取数据就用多个协程的方式。但是容易超频,所以想着写一个限流的东东。网上…

    Go语言 2023年5月25日
    047
  • GO后端开发+VUE实列

    因为我是从java转到go,代码结构跟我之前用java的很像 在这里只浅显的实战运用,没有过多理论讲解 工作环境:IDE:Goland , Go 1.17.7 框架 Gin+Gor…

    Go语言 2023年5月25日
    061
  • GO环境配置

    一、环境安装及配置 引用链接:Go语言环境安装及配置 Go版本安装 百度网盘msi地址:版本v1.18.1提取码:m1mc GoLand工具 链接:【版本2020.1】提取码:7x…

    Go语言 2023年5月25日
    074
  • golang 标准库template的代码生成

    最近,随着 antd Pro v5 的升级,将项目进行了升级,现在生成的都是 ts 代码。这个项目的自动生成代码都是基于 golang 的标准库 template 的,所以这篇博客…

    Go语言 2023年5月25日
    042
  • 系统调用跟踪——ls功能实现(二)

    在上篇文章中我们跟踪 ls命令看到了其所使用的这么几个系统调用: stat、openat、fstat、getdents、close、write等,这里再简单介绍下这几个系统调用的功…

    Go语言 2023年5月25日
    061
  • B树-查找

    B树系列文章 1. B树-介绍 2. B树-查找 3. B树-插入 4. B树-删除 查找 假设有一棵3阶B树,如下图所示。 下面说明在该B树中查找 52的过程 首先,从根结点出发…

    Go语言 2023年5月25日
    062
  • Go – 如何编写 ProtoBuf 插件 (三) ?

    上篇文章《Go – 如何编写 ProtoBuf 插件 (二) 》,分享了基于 自定义&#x90…

    Go语言 2023年5月25日
    063
  • Go语言实现大数开方程序

    Go语言的big包实现大数运算,但是有关大整数运算,似乎没有相应的开方程序。 这里给出的程序,实现了大整数的开方运算函数。该程序是基于大整数开方运算的算法实现的。 Go语言程序: …

    Go语言 2023年5月29日
    058
  • gRPC in ASP.NET Core 3.x — Protocol Buffer(2)Go语言的例子(下)

    第一篇文章(大约半年前写的):https://www.cnblogs.com/cgzl/p/11246324.html gRPC in ASP.NET Core 3.x &#821…

    Go语言 2023年5月29日
    0102
  • 为什么要避免在 Go 中使用 ioutil.ReadAll?

    原文链接: 为什么要避免在 Go 中使用 ioutil.ReadAll? ioutil.ReadAll 主要的作用是从一个 io.Reader 中读取所有数据,直到结尾。 在 Gi…

    Go语言 2023年5月25日
    051
  • 基于Go语言的xmind读写库,我主要用来把有道云笔记思维导图转为xmind

    xmind 基于go语言的xmind接口 本库主要加载xmind文件为json结构,保存文件时也用的json结构而不是xml结构 本库只做了最基本的主题添加功能,类似 &#…

    Go语言 2023年5月25日
    068
  • Go基础知识梳理(四)

    Go基础知识梳理(四) GO的哲学是”不要通过共享内存来通信,而是通过通信来共享内存”,通道是GO通过通信来共享内存的载体。 rumtime包常用方法 ru…

    Go语言 2023年5月25日
    042
  • go语言标准库

    学习go 语言,如果不知道标准库,那很多能力就不知道,标准库应该是程序员可以背下来的 bufio bytes container crypto database debug enc…

    Go语言 2023年5月29日
    054
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球