一文搞懂Golang中的接口

这篇具有很好参考价值的文章主要介绍了一文搞懂Golang中的接口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一文搞懂Golang中的接口

目录

接口

接口介绍

接口定义

实现接口

空接口

实现空接口

类型断言

使用类型断言

结构体实现多接口

接口嵌套

结构体值接收者和指针接收者实现接口的区别

代码案例


接口

接口介绍

Go语言中的接口(interface)是一组方法签名的集合,是一种抽象类型。接口定义了方法,但没有实现,而是由具体的类型(struct)实现这些方法,因此接口是一种实现多态的机制。

接口定义

Go语言中的接口定义语法如下:

type 接口名 interface {
    方法名1(参数1 类型1, 参数2 类型2) 返回值类型1
    方法名2(参数3 类型3) 返回值类型2
    ...
}

其中,接口名是一个标识符,方法名是一个标识符,参数和返回值都是类型。一个接口可以包含多个方法,每个方法的返回值类型可以是单个值、多个值、无返回值(void)或者是另一个接口类型。

实现接口

package main

import "fmt"

type animal interface {
    sound() string
}

type cat struct {
    name string
}

func (c cat) sound() string {
    return "meow"
}

type dog struct {
    name string
}

func (d dog) sound() string {
    return "woof"
}

func makeSound(a animal) {
    fmt.Println(a.sound())
}

func main() {
    c := cat{"Tom"}
    d := dog{"Fido"}

    makeSound(c)
    makeSound(d)
}

定义了一个 animal 接口,它包含了一个 sound() 方法,没有任何参数,返回一个字符串。然后我们定义了两个类型,一个是 cat,一个是 dog,它们都实现了 sound() 方法。最后我们定义了一个 makeSound() 函数,它接收一个实现了 animal 接口的对象,然后调用它的 sound() 方法打印出声音。在 main() 函数中,我们创建了一个 cat 和一个 dog 对象,然后分别传递给 makeSound() 函数进行测试。

实现接口的关键在于方法名和参数列表的匹配。只有当一个类型实现了一个接口中所有的方法,才能称之为这个接口的实现类型。在上面的例子中,catdog 都实现了 animal 接口中的 sound() 方法,因此它们都是 animal 接口的实现类型。

需要注意的是,Go语言中的接口是隐式实现的,也就是说,只要一个类型实现了接口中定义的所有方法,它就自动成为这个接口的实现类型,不需要显式地声明实现了哪个接口。这使得Go语言中的接口更加灵活,也更加容易使用。

空接口

在 Go 语言中,空接口是指一个没有任何方法的接口。空接口不仅没有方法,也没有任何需要实现的约束条件,因此可以被任何类型实现。因此,空接口也被称为万能接口。

空接口在 Go 语言中的作用非常广泛,可以用来表示任何类型的数据。在许多场景中,我们可能需要处理不同类型的数据,但是又不想为每个类型都定义一个新的接口,这时候就可以使用空接口。

实现空接口

package main

import (
	"fmt"
)

// 空接口
type EmptyInterface interface {
}

func main() {
	// 可以用空接口表示任何类型的数据
	var data1 EmptyInterface = 10
	var data2 EmptyInterface = "hello"
	var data3 EmptyInterface = []int{1, 2, 3}

	fmt.Println(data1)
	fmt.Println(data2)
	fmt.Println(data3)
}

在上面的示例中,定义了一个名为 EmptyInterface 的空接口。接着,在 main 函数中定义了三个变量 data1data2data3,它们都是 EmptyInterface 类型的变量,并分别赋值为整型、字符串和整型切片。可以看到,在输出这三个变量时,都直接使用了空接口类型的变量。

类型断言

在Go语言中,可以使用类型断言(type assertion)来判断一个接口实例的底层值是什么类型,并将其转换成对应的类型。类型断言的语法如下:

value, ok := interfaceVar.(Type)

其中,interfaceVar 是一个接口变量,Type 是一个具体的类型。如果 interfaceVar 的底层值是 Type 类型,则类型断言返回 interfaceVar 的底层值和 true;否则返回零值和 false

使用类型断言

package main

import (
	"fmt"
)

func main() {
	var i interface{}
	i = "hello"

	// 使用类型断言判断 i 的底层值是否为字符串类型
	if s, ok := i.(string); ok {
		fmt.Printf("i is a string: %s\n", s)
	} else {
		fmt.Println("i is not a string")
	}

	// 使用类型断言判断 i 的底层值是否为整数类型
	if n, ok := i.(int); ok {
		fmt.Printf("i is an integer: %d\n", n)
	} else {
		fmt.Println("i is not an integer")
	}
}

在上面的示例程序中,首先定义了一个空接口变量 i,并将其赋值为字符串 "hello"。然后,通过两次类型断言分别判断 i 的底层值是否为字符串类型和整数类型,最终输出判断结果。

输出结果为:

i is a string: hello
i is not an integer

需要注意的是,在使用类型断言时,如果底层值不是指定类型,则会触发运行时错误。因此,在使用类型断言时,通常会将其与条件语句配合使用,以避免出现运行时错误。而且类型断言一般使用在switch语句中。

结构体实现多接口

在Go语言中,结构体可以实现一个或多个接口,这使得结构体可以具备多个不同的行为。

首先定义一个结构体类型:

type Person struct {
    name string
    age  int
}

接着定义两个接口类型:

type Talker interface {
    Talk() string
}

type Runner interface {
    Run() string
}

Person结构体要实现这两个接口,需要实现它们的方法:

func (p Person) Talk() string {
    return "Hi, my name is " + p.name
}

func (p Person) Run() string {
    return "I can run " + strconv.Itoa(p.age) + " miles per hour"
}

这里的Talk()方法返回一个字符串,表示Person的自我介绍。Run()方法返回一个字符串,表示Person的奔跑速度。

最后可以创建一个Person实例,并将其赋值给Talker和Runner类型的变量:

func main() {
    p := Person{"Tom", 20}
    var t Talker = p
    var r Runner = p
    fmt.Println(t.Talk())
    fmt.Println(r.Run())
}

在这个示例中,我们将p赋值给t和r。t是Talker类型,因此它只能访问Talk()方法;r是Runner类型,因此它只能访问Run()方法。但是,由于Person实现了这两个接口,t和r都可以访问Talk()和Run()方法。

接口嵌套

Go语言中的接口嵌套是一种将多个接口组合成一个新接口的方法。它可以让程序员更灵活地组织和复用代码。

接口嵌套的语法格式为:一个接口类型可以嵌套多个接口类型,也可以嵌套一个包含多个接口类型的接口。

嵌套接口的语法格式为:

type Embed interface {
    I1
    I2
}

其中,I1I2是已经定义好的接口类型。Embed接口嵌套了I1I2两个接口类型,也就是说,Embed接口继承了I1I2两个接口的所有方法。这样,实现了Embed接口的类型也必须实现I1I2接口的所有方法。

接口嵌套可以实现代码的复用和组合。通过嵌套多个接口类型,可以定义一个新的接口类型,这个新的接口类型拥有多个接口类型的方法集合,可以更方便地调用这些方法。同时,由于接口类型的动态特性,我们可以在运行时动态地组合不同的接口类型,进一步实现代码的复用和扩展。

结构体值接收者和指针接收者实现接口的区别

1.在 Go 语言中,结构体可以通过实现接口来满足某个接口的约束条件。在实现接口时,可以使用值接收者或指针接收者。它们的主要区别在于如何处理结构体的拷贝和指针。

2.值接收者方法接收一个结构体值的副本作为接收者,而指针接收者方法接收一个结构体指针作为接收者。具体来说,值接收者方法会将结构体值拷贝一份,然后对副本进行操作,而指针接收者方法则直接操作原始结构体指针所指向的对象。

3.在实现接口时,使用值接收者方法和指针接收者方法的区别在于,使用值接收者方法实现接口时,只有结构体的值可以被传递给接口,而指针接收者方法实现接口时,可以传递结构体的指针或者任何实现了该结构体指针类型的类型。这是因为在 Go 语言中,可以通过对指针类型进行间接引用来访问结构体的字段。

4.指针接收者方法还具有一些其他的优点。例如,使用指针接收者可以避免在方法中对结构体进行拷贝,从而提高程序的性能。此外,指针接收者还可以用于修改结构体中的字段值。

5.在实现接口时,应根据实际情况选择值接收者方法或指针接收者方法。如果不需要修改结构体的字段,并且希望方法能够被传递给值类型的变量,那么使用值接收者方法就可以了。如果需要修改结构体的字段,或者希望方法能够被传递给指针类型的变量,那么就应该使用指针接收者方法。

代码案例

当使用值接收者(value receiver)实现接口时,接口会拷贝值接收者的值。而当使用指针接收者(pointer receiver)实现接口时,接口会拷贝指向值接收者的指针。这两种实现方式的主要区别在于对结构体的修改是否会影响接口中对应的值。

定义了一个接口 Geometry,并分别使用值接收者和指针接收者实现了两个结构体 RectangleCircle

package main

import (
	"fmt"
	"math"
)

type Geometry interface {
	area() float64
	perimeter() float64
}

type Rectangle struct {
	width, height float64
}

func (r Rectangle) area() float64 {
	return r.width * r.height
}

func (r Rectangle) perimeter() float64 {
	return 2*r.width + 2*r.height
}

type Circle struct {
	radius float64
}

func (c *Circle) area() float64 {
	return math.Pi * c.radius * c.radius
}

func (c *Circle) perimeter() float64 {
	return 2 * math.Pi * c.radius
}

func main() {
	r := Rectangle{width: 3, height: 4}
	c := Circle{radius: 5}

	fmt.Println("Rectangle")
	fmt.Println("Area: ", r.area())
	fmt.Println("Perimeter: ", r.perimeter())

	fmt.Println("\nCircle")
	fmt.Println("Area: ", c.area())
	fmt.Println("Perimeter: ", c.perimeter())

	// 值接收者实现的结构体修改不影响接口中对应的值
	r.width = 6
	fmt.Println("\nRectangle after modification")
	fmt.Println("Area: ", r.area())
	fmt.Println("Perimeter: ", r.perimeter())

	// 指针接收者实现的结构体修改会影响接口中对应的值
	c.radius = 7
	fmt.Println("\nCircle after modification")
	fmt.Println("Area: ", c.area())
	fmt.Println("Perimeter: ", c.perimeter())
}

输出结果为:

Rectangle
Area:  12
Perimeter:  14

Circle
Area:  78.53981633974483
Perimeter:  31.41592653589793

Rectangle after modification
Area:  24
Perimeter:  14

Circle after modification
Area:  153.93804002589985
Perimeter:  43.982297150257104

可以看到,当使用值接收者实现 Rectangle 结构体时,结构体中的修改不会影响接口中对应的值;而使用指针接收者实现 Circle 结构体时,结构体中的修改会影响接口中对应的值。文章来源地址https://www.toymoban.com/news/detail-455877.html

到了这里,关于一文搞懂Golang中的接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【MySQL】一文搞懂 MySQL 中的事务

    谈事务,一般就是说数据库事务。本篇文章以 MySQL 为例谈一谈事务。 MySQL 的 Indndb 引擎和 bdb 引擎支持事务。MySQL 的myisam ,memory 等存储引擎是不支持事务的。 事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务具体四大特性,也就是经常说的 ACID ,常用的MySQL、Sq

    2024年02月09日
    浏览(29)
  • 一文搞懂 MySQL 中的常用函数及用法

    MySQL是一种常用的关系型数据库管理系统,它提供了许多内置函数来处理数据。本文将介绍MySQL中的各种常用函数,包括字符串函数、日期函数、数学函数、聚合函数等。 1.1CONCAT函数 CONCAT函数用于将两个或多个字符串连接在一起。它的语法如下: 其中,str1、str2等为要连接的

    2024年02月10日
    浏览(28)
  • 一文搞懂UART、RS232、RS485、TTL等常用的接口与协议

    PC机常用的按照接口数量细分为A型(15针),B型(25针),C型(37针),D型(50针),E型(9针)。其中,串行通信常用的是RS232——9针的DB9接口,显示器用的是VGA——15针的DB15接口。现在的笔记本电脑都已取消这种接口,一方面是因为这种接口比较笨重、逐渐被市场淘汰,另

    2024年02月01日
    浏览(33)
  • 一文搞懂深度信念网络!DBN概念介绍与Pytorch实战

    本文深入探讨了深度信念网络DBN的核心概念、结构、Pytorch实战,分析其在深度学习网络中的定位、潜力与应用场景。 关注TechLead,分享AI与云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员

    2024年02月11日
    浏览(33)
  • Linux | 一文带你真正搞懂Linux中的权限问题

    首先来说说权限的基本概念: a.限制人的 b.访问的对象天然可能没有这种“属性” 首先这么说吧,权限也可以理解成【一件事情是否允许被谁“做”】,这个“谁”在Linux中分为两种用户,我么吧下面马上说到 然后要明确权限包括什么: 权限 = 人 + 事物(文件)属性(rwx)

    2024年02月02日
    浏览(37)
  • 【C++漂流记】一文搞懂类与对象中的对象特征

    在C++中,类与对象是面向对象编程的基本概念。类是一种抽象的数据类型,用于描述对象的属性和行为。而对象则是类的实例,具体化了类的属性和行为。本文将介绍C++中类与对象的对象特征,并重点讨论了对象的引用。 相关链接: 一文搞懂类与对象的封装 一文搞懂C++中的

    2024年02月07日
    浏览(32)
  • 一文搞定idea中的根目录

    在IntelliJ IDEA中,一个项目只有一个 项目 根目录(Project Root),这个根目录在本地硬盘中存放着整个项目的内容。但是,在IDEA的项目结构中,可以有多个 内容 根目录(Content Root),这些内容根目录是相对于项目模块(Module)而言的,内容根目录进一步细分了项目中的不同部

    2024年03月19日
    浏览(28)
  • Golang 中的接口详解

    什么是接口:接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。 在Go语言中接口(interface)是一种类型,一种抽象的类型。 interface是一组method的集合,是duck-type programming的一种体现。 接口做的事情就像是定义一个协议(规则

    2024年02月13日
    浏览(32)
  • Golang 中的 io 包详解(二):组合接口

    Golang 中,接口可以通过嵌入多个其他接口组成组合接口。组合接口表示的是子接口的集合,具有所有子接口的方法,可以通过组合多个不同的接口组成一个更强大的抽象。本文主要介绍下 io 包中的组合接口。 是对Reader和Writer接口的组合,聚合了基本的读写操作。简单示例如

    2024年02月08日
    浏览(30)
  • 深入理解Golang中的接口与实例展示

    标题:深入理解Golang中的接口与实例展示 引言: Golang(Go)的接口是一项强大的特性,它为面向对象编程带来了灵活性和可维护性。本文将深入讲解Golang中的接口概念,从基础到实际应用,通过详细案例展示,帮助读者更好地掌握接口的使用和设计。 一、接口基础概念: 接

    2024年01月21日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包