Golang接口的定义与空接口及断言的使用示例

 更新时间:2023年04月11日 11:19:04   作者:富士康质检员张全蛋  
在 Golang 中,接口是一种类型,它是由一组方法签名组成的抽象集合。这篇文章主要为大家介绍了Golang接口的具体使用,希望对大家有所帮助,空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法口,也因此,我们可以说所有类型都至少实现了空接口

1. Golang中的接口

在Go语言中接口(interface)是一种类型,一种抽象的类型。

接口(interface)定义了一个对象的行为规范, 只定义规范不实现 ,由具体的对象来实现规范的细节 。

实现接口的条件:

一个对象只要全部实现了接口中的方法 ,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。

2. 为什么要使用接口

下面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码

如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去

那我们能不能把它们当成“能叫的动物”来处理呢?

type Cat struct {
  Name string
}
func (c Cat) Say() string { 
  return c.Name + ":喵喵喵" 
}
type Dog struct {
  Name string
}
func (d Dog) Say() string { 
  return d.Name + ": 汪汪汪" 
}
func main() {
    c := Cat{Name: "小白猫"} // 小白猫:喵喵喵
    fmt.Println(c.Say())
    d := Dog{"阿黄"}
    fmt.Println(d.Say()) // 阿黄: 汪汪汪
}
/*
小白猫:喵喵喵
阿黄: 汪汪汪
*/

3. 定义一个Usber接口(从下往上转换)

定义一个 Usber 接口让 Phone 和 Computer 结构体实现这个接口

//1.接口是一个规范
type Usber interface {
    getName() string
}
//2.如果接口里面有方法的话,必要要通过结构体或者通过自定义类型实现这个接口
type Phone struct {
    Name string
}
type Computer struct {
    Brand string
}
func (c *Computer) getName() string {
    return c.Brand
}
//3.手机要实现usb接口的话必须得实现usb接口中的所有方法
func (p *Phone) getName() string {
    return p.Name
}
func main() {
    p := &Phone{
    Name: "华为手机",
    }
    c := &Computer{
    Brand: "联想电脑",
    }
    var p1 Usber // golang中接口就是一个数据类型
    p1 = p // 表示手机实现Usb接口
    fmt.Println(p1.getName())
    //接口使用场景,处理相同类型的数据
    newName := transData(p)
    newName1 := transData(c)
    fmt.Println(newName, newName1)
    }
    func transData(usber Usber) string {
        name := usber.getName()
        return fmt.Sprintf("%s%s", name, "处理后")
}

当我们要去处理同一数据类型的时候这个数据的时候,比如猫 狗是同一类数据类型。

像k8s的deployment,pod,configmap,secretd等等这些资源的时候,它都是k8s的一个资源,在获取列表的时候会对其做数据处理,比如要对其进行数据排序,那么只需要对这个接口进行排序就行了,不需要对每个资源都去写一遍排序的方法,那么这样不是很冗余吗?

4. 空接口

1. 空接口说明

  • Golang中空接口也可以直接当做类型来使用,可以表示任意类型 (泛型概念,最大的特点)
  • Golang 中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口。
  • 空接口表示没有任何约束,因此任何类型变量都可以实现空接口。
  • 空接口在实际项目中用的是非常多的,用空接口可以表示任意数据类型

2. 空接口作为函数的参数

//空接口作为函数的参数
func show(a interface{}) {
    fmt.Printf("值:%v 类型:%T\n", a, a) }
    func main() { 
    show(20) // 值:20 类型:int 
    show("你好golang") // 值:你好golang 类型:string 
    slice := []int{1, 2, 34, 4} 
    show(slice) // 值:[1 2 34 4] 类型:[]int 
    }

printf println是可以接受任何参数的,func Printf(format string , a ...interface{})可以看到这里可以接受任何空接口类型,...类似于切片类型。

func test(a int, b ...interface{}) {
    for _, v := range b {
        fmt.Printf("%v,%T \n", v, v)
    }
}
func main() {
    test(1, "a", 22, []string{"1"})
}
a,string 
22,int 
[1],[]string 

3. 切片实现空接口

切片和map是同一类型的元素,有了空接口,在同一个切片同一个map中就可以将任何类型的数据放进去。

func main() { 
    var slice = []interface{}{"张三", 20, true, 32.2}
    fmt.Println(slice) // [张三 20 true 32.2] 
}

4. map 的值实现空接口

func main() { // 空接口作为 map 值 
var studentInfo = make(map[string]interface{}) 
studentInfo["name"] = "张三" 
studentInfo["age"] = 18 studentInfo["married"] = false
fmt.Println(studentInfo) // [age:18 married:false name:张三] }

类型断言(从上往下转换,接口类型转化为具体类型)

  • 一个接口的值(简称接口值)是由一个具体类型和具体类型的值两部分组成的。
  • 这两部分分别称为接口的动态类型和动态值。(一个空接口,可以是结构体,指针,布尔各种类型。它其实是动态的,你传递什么都可以,这就叫做动态类型和动态值)
  • 如果我们想要判断空接口中值的类型,那么这个时候就可以使用类型断言
  • 其语法格式: x.(T)

x : 表示类型为 interface{}的变量

T : 表示断言 x 可能是的类型

断言返回两个值,一个是断言是否转化成果,一个是转化结果,注意空接口类型是空接口类型。

    var str interface{}
    str = "hello"
    str = str + "sss"  //这样写是会报错的,因为空接口类型不是字符串类型,需要断言转化才可以
type test1 struct {
    name string
    age  int
}
func main() {
    var t interface{}
    //未断言前没有结构体的特征,需要断言转化为结构体指针
    t = &test1{
        name: "hh",
        age:  12,
    }
    v, ok := t.(*test1)  //这里其实就是做了一个类型转化,这里的类型就变为来结构体指针类型
    if ok {
        fmt.Printf("类型:%T 值:%#v\n", v, v)
    } else {
        fmt.Println("xxx")
    }
}
类型:*main.test1 值:&main.test1{name:"hh", age:12}

转化为具体类型之后,那么具体类型的方法是都可以去调用的,空接口是不能访问属性和方法的。转化为具体的类型之后就可以访问其属性和方法。

值接收者和指针接收者(节省内存)

1. 值接收者

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。

在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。

type Usb interface { 
    Start() 
    Stop() 
}
type Phone struct { 
Name string 
}
func (p Phone) Start() {
fmt.Println(p.Name, "开始工作") 
}
func (p Phone) Stop() {
fmt.Println("phone 停止") 
}
func main() { 
    phone1 := Phone{  // 一:实例化值类型 
    Name: "小米手机", 
    }
    var p1 Usb = phone1 //phone1 实现了 Usb 接口 phone1 是 Phone 类型 
    p1.Start() 
    
    phone2 := &Phone{ // 二:实例化指针类型 
      Name: "苹果手机", 
    }
    var p2 Usb = phone2 //phone2 实现了 Usb 接口 phone2 是 *Phone 类型 
    p2.Start() //苹果手机 开始工作 
}

2. 指针接收者

  • 指针类型的接收者由一个结构体的指针组成
  • 由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。
  • 这种方式就十分接近于其他语言中面向对象中的 this 或者 self 。
  • 例如我们为 Person 添加一个 SetAge 方法,来修改实例变量的年龄。

3. 指针类型接收者

使用时机

注:并不是所有情况下都希望修改数据

  • 需要修改接收者中的值
  • 接收者是拷贝代价比较大的大对象
  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

从使用场景上面来说,基本上都会使用指针,如果使用了第三方的包,第三方包的某些返回值它只是一个值类型,所以第三方类型返回什么类型我们就使用什么类型,针对第三方包。

到此这篇关于Golang接口的定义与空接口及断言的使用示例的文章就介绍到这了,更多相关Golang接口的定义内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang常用包使用介绍

    Golang常用包使用介绍

    标准的Go语言代码库中包含了大量的包,并且在安装Go的时候多数会自动安装到系统中。我们可以在$GOROOT/src/pkg目录中查看这些包。下面简单介绍一些我们开发中常用的包
    2022-09-09
  • 详解Golang实现请求限流的几种办法

    详解Golang实现请求限流的几种办法

    这篇文章主要介绍了详解Golang实现请求限流的几种办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • go语言中布隆过滤器低空间成本判断元素是否存在方式

    go语言中布隆过滤器低空间成本判断元素是否存在方式

    这篇文章主要为大家介绍了go语言中布隆过滤器低空间成本判断元素是否存在方式详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Golang中基础的命令行模块urfave/cli的用法说明

    Golang中基础的命令行模块urfave/cli的用法说明

    这篇文章主要介绍了Golang中基础的命令行模块urfave/cli的用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 如何使用腾讯云go sdk 查询对象存储中最新文件

    如何使用腾讯云go sdk 查询对象存储中最新文件

    这篇文章主要介绍了使用腾讯云go sdk 查询对象存储中最新文件,这包括如何创建COS客户端,如何逐页检索对象列表,并如何对结果排序以找到最后更新的对象,我们还展示了如何优化用户体验,通过实时进度更新和检索多个文件来改进程序,需要的朋友可以参考下
    2024-03-03
  • RabbitMq如何做到消息的可靠性投递

    RabbitMq如何做到消息的可靠性投递

    现在的一些互联网项目或者是高并发的项目中很少有没有引入消息队列的。 引入消息队列可以给这个项目带来很多的好处,这篇文章主要为大家介绍了RabbitMq如何做到消息的可靠性投递,有需要的朋友可以借鉴参考下
    2022-12-12
  • goland中导包报红和go mod问题

    goland中导包报红和go mod问题

    这篇文章主要介绍了goland中导包报红和go mod问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Go语言context test源码分析详情

    Go语言context test源码分析详情

    这篇文章主要介绍了Go语言context test源码分析详情,关于context test,测试对象是context包,测试包的包名是context_test,下面将对context test源码进行分析,需要的朋友可以参考一下,希望对你有所帮助
    2022-02-02
  • 详解Go语言中rand(随机数)包的使用

    详解Go语言中rand(随机数)包的使用

    在Golang中,有两个包提供了rand,分别为math/rand和crypto/rand对应两种应用场景。math/rand包实现了伪随机数生成器。也就是生成 整形和浮点型;crypto/rand包实现了用于加解密的更安全的随机数生成器。本文就来和大家详细讲讲math/rand的使用
    2022-08-08
  • 分享6个Go处理字符串的技巧小结

    分享6个Go处理字符串的技巧小结

    这篇文章主要介绍了分享6个Go处理字符串的技巧小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12

最新评论