一文带你了解Go语言中接口的使用

目录
  • 接口
  • 接口的实现
  • 接口类型变量
  • 空接口
  • 类型断言
    • 类型断言变种 type switch
  • 小结

接口

Go 语言中,接口是一种抽象的类型,是一组方法的集合。接口存在的目的是定义规范,而规范的细节由其他对象去实现。我们来看一个例子:

import "fmt"

type Person struct {
    Name string
}

func main() {
    person := Person{Name: "cmy"}
    fmt.Println(person) // {cmy}
}

上述代码定义了结构体 Personmain 函数创建了此结构体的变量 person,然后通过 fmt 包里的 Println 函数打印这个结构体,打印结果为 {cmy}。在此基础上,我们改造一下代码:

import "fmt"

type Person struct {
    Name string
}

func (p Person) String() string {
    return fmt.Sprintf("name: %s", p.Name)
}

func main() {
    person := Person{Name: "cmy"}
    fmt.Println(person) // name: cmy
}

新改造的代码里为结构体 Person 添加一个结构体方法 String() string,方法的返回结果是对 name 进行格式化,我们再打印一下结构体,观察结果发现是 String() 方法返回的值,而不是 {cmy}。 为什么是这样呢?这是因为 fmt.Println(T) 函数的实现细节里,会对结构体进行判断,如果结构体实现了 Stringer 接口,则会直接打印 String() 方法的返回值。以下是 Stringer 接口的代码:

type Stringer interface {
    String() string
}

结构体实现了这个接口,也就意味着遵守这个接口所定义的规范,fmt.Println(T) 函数发现结构体有这个规范,因此就会根据规范来打印信息。基于 Stringer 接口,我们来看看接口的语法格式:

type XXX interface {
    // methods
}

1、type

接口的声明,必须以 type 关键字开头。

2、接口名

推荐驼峰式命名法,首字母大写的方法名可以在包外访问,小写的只能在包内访问。

3、interface

接口的标识。

4、接口体

大括号里面声明规范,也就是声明方法,方法必须具有名字。

接口的实现

Go 语言里,接口的实现不是基于接口,而是基于方法。如果一个自定义类型拥有了某个接口的所有方法,那么这个自定义类型就实现这个接口。接口的实现在上述的例子中有所体现,Person 结构体定义了 String() string 方法,拥有了 Stringer 接口的所有方法,因此实现了 Stringer 接口。

一个自定义类型可以实现多个接口

type A interface {
        a()
}

type B interface {
        b()
}
type Person struct {
        Name string
}

func (p Person) a() {
}

func (p Person) b() {
}

A 接口声明了 a 方法, B 接口声明了 b 方法,Person 结构体定义了 ab 两个方法,因此 Person 结构体实现了 AB 两个接口。

接口类型变量

一旦接口被定义,它就可以用于声明变量。

import "fmt"

type A interface {
}

func main() {
    var a A
    fmt.Println(a) // <nil>
}

如果只声明接口变量,不初始化,变量的值默认为 nil,因为接口类型实际上是一个指针。若为接口赋初值,需要选择一个合法的值,即被赋值的基类必须实现这个接口。

空接口

Go 语言里面可以认为所有类型实现了空接口,因为空接口没有任何的方法。

import "fmt"

type EmptyInterface interface {
}

func main() {
    var a EmptyInterface = 1
    var b EmptyInterface = true
    var c EmptyInterface = "hello"
    var d EmptyInterface = 3.14
    var e EmptyInterface = 'c'
    fmt.Println(a, b, c, d, e) // 1 true hello 3.14 99
}

所有类型都实现空接口,因此空接口变量可以被赋初值为任意类型的值或变量。

类型断言

Go 语言支持类型断言操作,通过这个操作,可以还原接口变量的右值(被赋的初值)。类型断言的语法形式通常为:

v, ok := a.(T)

如果断言成功,那么 v 的值为接口变量的值,ok 的值为 true;如果断言失败,v 的值为 T 类型的零值,ok 的值为 false

类型断言变种 type switch

通过 type switch 的方式,可以判断接口变量属于哪种动态类型。

import "fmt"

type EmptyInterface interface {
}

func main() {
    var a EmptyInterface = 1
    switch a.(type) {
    case string:
	fmt.Println("a 的右值类型为 string")
    case int:
	fmt.Println("a 的右值类型为 int")
    case bool:
	fmt.Println("a 的右值类型为 bool")
    case float64:
	fmt.Println("a 的右值类型为 float64")
    }
}

小结

本文先是对接口的定义进行介绍,然后通过一个例子,了解了接口其中的一个应用场景和引出接口的语法格式以及实现的方法,然后介绍了空接口的特点和类型断言,最后介绍了变种的类型断言 type switch 的应用例子。

到此这篇关于一文带你了解Go语言中接口的使用的文章就介绍到这了,更多相关Go语言接口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 从零开始学Golang的接口

    目录 前言 1.为什么需要接口? 2.接口是什么?如何定义? 3.接口实战初体验 4.如何测试是否已实现该接口? 5.空接口&类型断言 6.接口零值 7.一个类型实现多个接口 8.指针与值类型实现接口的区别 9.接口嵌套 前言 接口在面向对象编程中是经常使用的招式,也是体现多态很重要的手段.是的.Golang中也有接口这玩意儿. 1.为什么需要接口? 多数情况下,数据可能包含不同的类型,却会有一个或者多个共同点,这些共同点就是抽象的基础.前文讲到的Golang继承解决的是is-a的问题,单一继承

  • Go语言的接口详解

    目录 1.接口的用途 2.类型断言 3.类型选择 4.空接口 5.匿名空接口 6.实现多个接口 7.接口嵌套 8.接口零值 9.make和new的区别 总结 接口就是一系列方法的集合(规范行为) 在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为,规范子类对象的行为. 在 Go 语言中的接口是非侵入式接口(接口没了,不影响代码),侵入式接口(接口没了,子类报错) Go 也是鸭子类型,比如我现在有个鸭子类,内有 speak 方法和 run 方法,子类只要实现了 speak 和 run,我

  • Golang接口使用教程详解

    目录 前言 一.概述 二.接口类型 2.1 接口的定义 2.2 实现接口的条件 2.3 为什么需要接口 2.4 接口类型变量 三.值接收者和指针接收者 3.1 值接收者实现接口 3.2 指针接收者实现接口 四.类型与接口的关系 4.1 一个类型实现多个接口 4.2 多种类型实现同一接口 五.接口嵌套 六.空接口 七.类型断言 总结 前言 go语言并没有面向对象的相关概念,go语言提到的接口和java.c++等语言提到的接口不同,它不会显示的说明实现了接口,没有继承.子类.implements关键

  • 深入Golang的接口interface

    目录 前言 接口转换的原理 实现多态 前言 go不要求类型显示地声明实现了哪个接口,只要实现了相关的方法即可,编译器就能检测到 空接口类型可以接收任意类型的数据: type eface struct { // _type 指向接口的动态类型元数据 // 描述了实体类型.包括内存对齐方式.大小等 _type *_type // data 指向接口的动态值 data unsafe.Pointer } 空接口在赋值时,_type 和 data 都是nil.赋值后,_type 会指向赋值的数据元类型,d

  • Go语言接口的用法详解

    一.接口的定义和好处 我们都知道接口给类提供了一种多态的机制,什么是多态,多态就是系统根据类型的具体实现完成不同的行为. 以下代码简单说明了接口的作用 package main import ( "fmt" "io" "net/http" "os" ) // init 在main 函数之前调用 func init() { if len(os.Args) != 2 { fmt.Println("Usage: ./exa

  • 一文带你了解Go语言中接口的使用

    目录 接口 接口的实现 接口类型变量 空接口 类型断言 类型断言变种 type switch 小结 接口 在 Go 语言中,接口是一种抽象的类型,是一组方法的集合.接口存在的目的是定义规范,而规范的细节由其他对象去实现.我们来看一个例子: import "fmt" type Person struct { Name string } func main() { person := Person{Name: "cmy"} fmt.Println(person) //

  • 一文带你了解Go语言中的单元测试

    目录 基本概念 示例一:取整函数基本测试 示例二:Fail()函数 示例三:FailNow函数 实例四:Log和Fetal函数 基本概念 上一节提到,代码完成的标准之一还包含了单元测试,这部分也是很多开发流程中不规范的地方.写过单元测试的开发人员应该理解,单元测试最核心的价值是为了证明:为什么我写的代码是正确的?也就是从逻辑角度帮你检查你的代码.但是另外一方面,如果从单元测试覆盖率角度来看,单元测试也是非常耗时的,几乎是三倍于你代码的开发时间,所以在很多迭代速度非常快的项目中,单元测试就几乎没人

  • 一文带你入门Go语言中定时任务库Cron的使用

    目录 前言 快速开始 安装 导入 Demo Cron表达式格式 标准格式 预定义时间表 常用的方法介绍 new() AddJob() AddFunc() Start() 相关推荐 Go第三方库之cronexpr——解析 crontab 表达式 总结 前言 在平时的开发需求中,我们经常会有一些重复执行的操作需要触发执行,和系统约个时间,在几点几分几秒或者每隔几分钟跑一个任务,说白了就是定时任务,,想必大家第一反应都是linux的Crontab.其实定时任务不止使用系统自带的Crontab,在Go语

  • 一文带你了解Go语言中的类型断言和类型转换

    目录 类型断言 类型判断 为什么需要断言 类型转换 什么时候使用类型转换 类型为什么称为转换 类型结论 在Go中,类型断言和类型转换是一个令人困惑的事情,他们似乎都在做同样的事情. 下面是一个类型断言的例子: var greeting interface{} = "hello world" greetingStr := greeting.(string) 接着看一个类型转换的例子: greeting := []byte("hello world") greeting

  • 一文带你了解Go语言中的指针和结构体

    目录 前言 指针 指针的定义 获取和修改指针所指向变量的值 结构体 结构体定义 结构体的创建方式 小结 前言 前面的两篇文章对 Go 语言的基础语法和基本数据类型以及几个复合数据类型进行介绍,本文将对 Go 里面的指针和结构体进行介绍,也为后续文章做铺垫. 指针 在 Go 语言中,指针可以简单理解是一个地址,指针类型是依托于某一个类型而存在的,例如 Go 里面的基本数据类型 int.float64.string 等,它们所对应的指针类型为 *int.*float64.*string等. 指针的定

  • 一文带你掌握Go语言中的文件读取操作

    目录 os 包 和 bufio 包 os.Open 与 os.OpenFile 以及 File.Read 读取文件操作 bufio.NewReader 和 Reader.ReadString 读取文件操作 小结 os 包 和 bufio 包 Go 标准库的 os 包,为我们提供很多操作文件的函数,如 Open(name) 打开文件.Create(name) 创建文件等函数,与之对应的是 bufio 包,os 包是直接对磁盘进行操作的,而 bufio 包则是带有缓冲的操作,不用每次都去操作磁盘.

  • 一文带你了解Go语言中方法的调用

    目录 前言 方法 方法的调用 Receiver 参数类型的选择 方法的约束 小结 前言 在前面的 一文熟悉 Go 函数 文章中,介绍了 Go 函数的声明,函数的几种形式如匿名函数.闭包.基于函数的自定义类型和函数参数详解等,而本文将对方法进行介绍,方法的本质就是函数,介绍方法的同时也会顺带对比其与函数的不同之处. 方法 在 Go 中,我们可以为任何的数据类型定义方法(指针或接口除外),现在让我们看一看方法的声明和组成部分以及与函数有什么不同之处. type Person struct { age

  • 一文带你熟悉Go语言中函数的使用

    目录 函数 函数的声明 Go 函数支持变长参数 匿名函数 闭包 init 函数 函数参数详解 形式参数与实际参数 值传递 函数是一种数据类型 小结 函数 函数的英文单词是 Function,这个单词还有着功能的意思.在 Go 语言中,函数是实现某一特定功能的代码块.函数代表着某个功能,可以在同一个地方多次使用,也可以在不同地方使用.因此使用函数,可以提高代码的复用性,减少代码的冗余. 函数的声明 通过案例了解函数的声明有哪几部分: 定义一个函数,实现两个数相加的功能,并将相加之后的结果返回. f

  • 一文带你熟悉Go语言中的分支结构

    目录 分支结构 if 单分支 if 双分支 if-else 多分支 if - else if - else 在 if 语句中声明变量 switch 示例 switch 分支当 if 分支使用 在 switch 语句中声明变量 fallthrough 小结 分支结构 分支结构是结构化程序设计中的基础.针对分支结构,Go 提供了两种语句形式,一种是 if,另一种是 switch. if if 语句是 Go 中最常用.最简单的分支控制结构,它分为单分支.双分支以及多分支三种用法.if 语句会根据布尔变

  • 一文带你了解C语言中的动态内存管理函数

    目录 1.什么是动态内存管理 2.为什么要有动态内存管理 3.如何进行动态内存管理 3.1 malloc 3.2 free 3.3 calloc 3.4 realloc 总结 1.什么是动态内存管理 平时我们写代码,一种非常常见的写法是: int a = 0; // 创建一个变量 int arr[10] = {0}; // 创建一个数组 当你创建变量a的时候,其实是向内存中申请了4个字节的空间来存放一个整数.而当你创建数组arr的时候,是向内存中申请了40个字节的空间来存放10个整数.当你这么写

随机推荐