Go语言中的interface理解

golang技术随笔(一)深入理解interface Go语言的主要设计者之一罗布·派克( Rob Pike)曾经说过,如果只能选择一个Go语言的特 性移植到其他语言中,他会选择接口。可见接口在golang中的地位,及其对gloang这门语言所带来的活力。      golang中的interface是什么 接口相当于是一份契约,它规定了一个对象所能提供的一组操作。要理解golang中接口的概念我们最好还是先来看看别的现代语言是如何实现 阅读详情

1、interface 是一种类型

首先 interface 是一种类型,从它的定义可以看出来用了 type 关键字,更准确的说 interface 是一种具有一组方法的类型,这些方法定义了 interface 的行为。

go 允许不带任何方法的 interface ,这种类型的 interface 叫 empty interface。

如果一个类型实现了一个 interface 中所有方法,我们说类型实现了该 interface,所以所有类型都实现了 empty interface,因为任何一种类型至少实现了 0 个方法。go 没有显式的关键字用来实现 interface,只需要实现 interface 包含的方法即可。


2、interface 变量存储的是实现者的值

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
      
//1
type I interface {
Get() int
Set( int)
}
//2
type S struct {
Age int
}
func(s S) Get()int {
return s.Age
}
func(s *S) Set(age int) {
s.Age = age
}
//3
func f(i I){
i.Set( 10)
fmt.Println(i.Get())
}
func main() {
s := S{}
f(&s) //4
}

这段代码在 #1 定义了 interface I,在 #2 用 struct S 实现了 I 定义的两个方法,接着在 #3 定义了一个函数 f 参数类型是 I,S 实现了 I 的两个方法就说 S 是 I 的实现者,执行 f(&s) 就完了一次 interface 类型的使用。

interface 的重要用途就体现在函数 f 的参数中,如果有多种类型实现了某个 interface,这些类型的值都可以直接使用 interface 的变量存储。

      
1
2
3
4
      
s := S{}
var i I //声明 i
i = &s //赋值 s 到 i
fmt.Println(i.Get())

不难看出 interface 的变量中存储的是实现了 interface 的类型的对象值,这种能力是 duck typing。在使用 interface 时不需要显式在 struct 上声明要实现哪个 interface ,只需要实现对应 interface 中的方法即可,go 会自动进行 interface 的检查,并在运行时执行从其他类型到 interface 的自动转换,即使实现了多个 interface,go 也会在使用对应 interface 时实现自动转换,这就是 interface 的魔力所在。

3、如何判断 interface 变量存储的是哪种类型

一个 interface 被多种类型实现时,有时候我们需要区分 interface 的变量究竟存储哪种类型的值,go 可以使用 comma, ok 的形式做区分 value, ok := em.(T):em 是 interface 类型的变量,T代表要断言的类型,value 是 interface 变量存储的值,ok 是 bool 类型表示是否为该断言的类型 T。


      
1
2
3
4
      
if t, ok := i.(*S); ok {
fmt.Println( "s implements I", t)
}

ok 是 true 表明 i 存储的是 *S 类型的值,false 则不是,这种区分能力叫 Type assertions (类型断言)。

如果需要区分多种类型,可以使用 switch 断言,更简单直接,这种断言方式只能在 switch 语句中使用。

      
1
2
3
4
5
6
7
      
switch t := i.( type) {
case *S:
fmt.Println( "i store *S", t)
case *R:
fmt.Println( "i store *R", t)
}

4、空的 interface

interface{} 是一个空的 interface 类型,根据前文的定义:一个类型如果实现了一个 interface 的所有方法就说该类型实现了这个 interface,空的 interface 没有方法,所以可以认为所有的类型都实现了 interface{}。如果定义一个函数参数是 interface{} 类型,这个函数应该可以接受任何类型作为它的参数。


      
1
2
      
func doSomething(v interface{}){
}

如果函数的参数 v 可以接受任何类型,那么函数被调用时在函数内部 v 是不是表示的是任何类型?并不是,虽然函数的参数可以接受任何类型,并不表示 v 就是任何类型,在函数 doSomething 内部 v 仅仅是一个 interface 类型,之所以函数可以接受任何类型是在 go 执行时传递到函数的任何类型都被自动转换成 interface{}。go 是如何进行转换的,以及 v 存储的值究竟是怎么做到可以接受任何类型的,感兴趣的可以看看 Russ Cox 关于 interface 的实现 。

既然空的 interface 可以接受任何类型的参数,那么一个 interface{}类型的 slice 是不是就可以接受任何类型的 slice ?

      
1
2
3
4
5
6
7
8
9
10
      
func printAll(vals []interface{}) { //1
for _, val := range vals {
fmt.Println(val)
}
}
func main(){
names := [] string{ "stanley", "david", "oscar"}
printAll(names)
}

上面的代码是按照我们的假设修改的,执行之后竟然会报 cannot use names (type []string) as type []interface {} in argument to printAll 错误,why?

这个错误说明 go 没有帮助我们自动把 slice 转换成 interface{} 类型的 slice,所以出错了。go 不会对 类型是interface{} 的 slice 进行转换 。为什么 go 不帮我们自动转换,一开始我也很好奇,最后终于在 go 的 wiki 中找到了答案 https://github.com/golang/go/wiki/InterfaceSlice 大意是 interface{} 会占用两个字长的存储空间,一个是自身的 methods 数据,一个是指向其存储值的指针,也就是 interface 变量存储的值,因而 slice []interface{} 其长度是固定的N*2,但是 []T 的长度是N*sizeof(T),两种 slice 实际存储值的大小是有区别的(文中只介绍两种 slice 的不同,至于为什么不能转换猜测可能是 runtime 转换代价比较大)。

但是我们可以手动进行转换来达到我们的目的。

      
1
2
3
4
5
      
var dataSlice [] int = foo()
var interfaceSlice [] interface{} = make([] interface{}, len(dataSlice))
for i, d := range dataSlice {
interfaceSlice[i] = d
}

5、interface 的实现者的 receiver 如何选择

在我们上文的例子中调用 f 是 f(&s) 也就是 S 的指针类型,为什么不能是 f(s) 呢,如果是 s 会有什么问题?改成 f(s) 然后执行代码。


      
1
2
      
cannot use s (type S) as type I in argument to f:
S does not implement I (Set method has pointer receiver)

这个错误的意思是 S 没有实现 I,哪里出了问题?关键点是 S 中 set 方法的 receiver 是个 pointer *S 。

interface 定义时并没有严格规定实现者的方法 receiver 是个 value receiver 还是 pointer receiver,上面代码中的 S 的 Set receiver 是 pointer,也就是实现 I 的两个方法的 receiver 一个是 value 一个是 pointer,使用 f(s)的形势调用,传递给 f 的是个 s 的一份拷贝,在进行 s 的拷贝到 I 的转换时,s 的拷贝不满足 Set 方法的 receiver 是个 pointer,也就没有实现 I。go 中函数都是按值传递即 passed by value。

那反过来会怎样,如果 receiver 是 value,函数用 pointer 的形式调用?

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
      
type I interface {
Get() int
Set( int)
}
type SS struct {
Age int
}
func (s SS) Get() int {
return s.Age
}
func (s SS) Set(age int) {
s.Age = age
}
func f(i I) {
i.Set( 10)
fmt.Println(i.Get())
}
func main(){
ss := SS{}
f(&ss) //ponter
f(ss) //value
}

I 的实现者 SS 的方法 receiver 都是 value receiver,执行代码可以看到无论是 pointer 还是 value 都可以正确执行。

导致这一现象的原因是什么?

如果是按 pointer 调用,go 会自动进行转换,因为有了指针总是能得到指针指向的值是什么,如果是 value 调用,go 将无从得知 value 的原始值是什么,因为 value 是份拷贝。go 会把指针进行隐式转换得到 value,但反过来则不行。

对于 receiver 是 value 的 method,任何在 method 内部对 value 做出的改变都不影响调用者看到的 value,这就是按值传递。

另一个说明上述现象的例子是这样的来自 https://play.golang.org/p/TvR758rfre

      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
      
package main
import (
"fmt"
)
type Animal interface {
Speak() string
}
type Dog struct {
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct {
}
//1
func (c *Cat) Speak() string {
return "Meow!"
}
type Llama struct {
}
func (l Llama) Speak() string {
return "?????"
}
type JavaProgrammer struct {
}
func (j JavaProgrammer) Speak() string {
return "Design patterns!"
}
func main() {
animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}

#1 Cat 的 speak receiver 是 pointer,interface Animal 的 slice,Cat 的值是一个 value,同样会因为 receiver 不一致而导致无法执行。

Go 学习笔记(35)— Go 接口 interface (接口声明、接口初始化、接口方法调用、接口运算、类型断言、类型查询、空接口) 1. 接口概念 接口是双方约定的一种合作协议。接口实现者不需要关心接口会被怎样使用,调用者也不需要关心接口的实现细节。接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式、类型及结构。 接口内部存放的具体类型变量被称为接口指向的“实例”。接口只有声明没有实现,所以定义一个新接口,通常又变成声明一个新接口, 定义接口和声明接口二者通用,代表相同的意思。 最常使用的接口字面量类型就是空接口 interface{} ,由于空接口的方法集为空,所以任意类型都被认为实现了空接口,任意类型的实例都可以赋值或传递给空 阅读详情

相关推荐

工作笔记05:imu、底盘车轮、单激光雷达外参校准(基于hdl_graph_slam建图和定位)

目录1. imu 校准1.1 IMU型号1.2 坐标定义1.2.1 大地坐标系(WGS84)1.2.2 当地地理坐标系(ENU)1.2.3 传感器坐标轴定义1.3 传感器校准2. 底盘车辆参数配置3. 单激光雷达校准参考文献 1. imu 校准 1.1 IMU型号 阅读IMU产品说明书,获得如下信息: Yesense YIS300 系列惯性传感系统 YIS300 系列包含: YIS300-U 惯性测量单元(IMU):输出经过校准的加速度和角速度值,同时也能够输出磁场强度信息。 YIS300-V 垂直参考系

穿林需独行的博客 4203

golang语言 []interface{}和interface{}

在Goland中有一种特殊类型:interface{} ,空接口。interface{} 类型是没有方法的接口。由于没有 implements 关键字,所以所有类型都至少实现了 0 个方法,所以 所有类型都实现了空接口。这意味着,如果编写一个函数以 interface{} 值作为参数,那么可以为该函数提供任何值,并且,[]interface{}在golang中也可以认为是interface{}。

西京刀客 4525

基于奥比中光Orbbec Astra Pro与ROS实现实时3D环境建模:orb_slam2实战指南

本文提供了一份详细的实战指南,介绍如何使用奥比中光Orbbec Astra Pro深度摄像头与ROS系统,部署并运行ORB-SLAM2算法,实现实时3D环境建模与定位。内容涵盖从驱动安装、环境配置、算法编译到摄像头标定与性能调优的全流程,旨在帮助开发者快速搭建一套高性价比的视觉SLAM系统。

weixin_29054399的博客 336

理解Golang中的[]interface{}和interface{}

理解Golang中的[]interface{}和interface{} 之前在开发Go项目操作Redis时,利用Do函数进行数据操作,在返回的interface{}类型的转换中踩了一个大坑。 Do(ctx, "HKEYS", "KEY") 在阅读源码中发现,Do方法的是一个[]interface{}切片 func (c *Redis) Do(ctx context.Context, commandName string, args ...interface{}) (interface{}, error)

qq_39220627的博客 7724

汇率波动率建模实战:从GARCH到EGARCH的金融时间序列分析

在金融时间序列分析中,波动率建模是量化市场风险的核心技术。其基本原理在于捕捉金融资产收益率序列中存在的波动聚集、尖峰厚尾等典型特征。通过建立条件异方差模型,如GARCH及其扩展模型,可以动态估计和预测未来波动率,这对于资产定价、风险管理和投资决策具有重要价值。在金融工程领域,该技术广泛应用于外汇、股票和衍生品市场。本文以汇率波动率建模为具体场景,详细阐述了如何使用Python中的arch库,从数据预处理、模型选型(包括GARCH、EGARCH等)、参数估计到样本外预测评估的全流程实践,并深入探讨了模型在应对

weixin_32629853的博客 374

海康工业相机 Could not find module MvCameraControl.dll(已解决)

【代码】海康摄像机 Could not find module MvCameraControl.dll(已解决)

hmbbpdx的博客 2224

全面讲解 Go 中的 interface{}

空接口可用于保存任何数据,它可以是一个有用的参数,因为它可以使用任何类型。要理解空接口如何工作以及如何保存任何类型,我们首先应该理解空接口名称背后的概念。 本文是 Go语言中文网组织的 GCTT 翻译,发布在 Go语言中文网公众号,转载请联系我们授权。 接口(interface{}) Jordan Oreilli[1] 对空接口的一个很好的定义: 接口是两件事物:它是一组方法,但它也是一种类型。 interface{} 类型是没有方法的接口。由于没有 implements 关键字,所有类型都至少

flynetcn的专栏 6996

Python爬虫之爬取并下载哔哩哔哩视频

它可以爬取并下载视频文件和音频文件!亲自使用过,太好用了。

2301_80124151的博客 3万+

接口的定义及实现

接口 普通类:只有具体实现 抽象类:具体实现和规范(抽象方法)都有 接口:只有规范,自己无法写方法,是专业的约束;约束和实现分离:面向接口编程 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。 OO的精髓,是对对象的抽象,最能体现这一点的就是接口。 声明类的关键字是class,声明接口的关键字是interface 作用 约束 定义一些方法,让不同的人实现 接口中方法定义:public abstract —

weixin_46649583的博客 1426

高斯过程的数学理解

G澳大利亚的过程是有益的,特别是当我们有少量数据时。当我在制造业担任数据科学家时,我们的团队使用这种算法来揭示我们接下来应该进行哪些实验条件。但是,此算法不如其他算法流行。在这篇博客中,我将通过可视化和 Python 实现来解释高斯过程 [1] 的数学背景。

gongdiwudu的专栏 3611

C++面向对象编程-继承与派生练习题

2、共同派生类 3、人员类Person的派生(虚基类的使用)

编程小鹏的博客 1193

如何理解Go语言的interface

在 Go 语言中,接口(Interface)的本质是,它通过和机制,将“做什么”(行为)与“如何做”(实现)解耦。

xuukai的博客 891

在VINS-FUSION上处理KITTI数据集(双目+GPS)

VINS-Fusion 是一个开源的实时多传感器状态估计库,主要由香港科技大学的沈邵劼教授领导的研究团队开发。它是 VINS-Mono(单目视觉惯性系统)的扩展,支持多种传感器组合,如双目、立体相机和IMU。

如果想成为中心,那么就到中心去吧。 1206

Go语言 interface 理解 & 与反射的关系

理解 interface 1、interface 是一种类型 准确来说,interface 是带有一组方法的一种类型,这些方法定义了 interface 的行为。如果一个类型实现了一个 interface 中所有方法,则该类型实现了该 interface。又因为 go 允许不带任何方法的interface存在,这种interface成为空interface。所以所有类型都实现了 empty interface,因为任何一种类型至少实现了 0 个方法。 go 没有显式的关键字用来实现 interfa

judgejames的博客 1404

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

go interface类型转换_如何理解Go语言的空接口interface{}

如何理解Go语言的空接口(interface{ })[图片来源于网络]终于更新了。。。❝一个空接口(也就是平时见得比较多的interface{})可以用来保存任何数据,因此,当我们在设计一个方法的时候,使用空接口作为参数可以变得很有用,因为空接口可以接收任何类型(int, string, []int......)❞InterfacesJordan Oreillic曾这样描述Go语言的in...

weixin_39901332的博客 1124

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

golang 初始化并赋值_Golang | 既是接口又是类型,interface是什么神仙用法?

今天是golang专题的第12篇文章,我们来继续聊聊interface的使用。在上一篇文章当中我们介绍了面向对象的一些基本概念,以及golang当中interface和多态的实现方法。今天我们继续来介绍interface当中其他的一些方法。万能类型interface在Java以及其他语言当中接口是一种写法规范,而在golang当中,interface其实也是一种值,它可以像是值一样传递。并且在它的...

weixin_39663729的博客 862

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Golang 入门系列(四)如何理解interface接口

Golang 入门系列(四)如何理解interface接口 前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友,可以先看看之前的文章。https://www.cnblogs.com/zhangweizhong/category/1275863.html 今天就正式开始写Go 的代码,讲讲如何理解interface接...

章为忠的专栏 193

go 语言 linux api,Go语言接口interface深入理解

接口是什么?Go 语言不是一种 “传统” 的面向对象编程语言:它里面没有类和继承的概念。但是 Go 语言里有非常灵活的 接口 概念,通过它可以实现很多面向对象的特性。接口提供了一种方式来 说明 对象的行为:如果谁能搞定这件事,它就可以用在这儿。简单的说,interface是一组method的组合,我们通过interface来定义对象的一组行为,但是这些method接口不需要去实现,并且interf...

weixin_42103128的博客 341

语言爬虫字段为空_如何理解Go语言的空接口interface{}

如何理解Go语言的空接口(interface{ })[图片来源于网络]终于更新了。。。❝一个空接口(也就是平时见得比较多的interface{})可以用来保存任何数据,因此,当我们在设计一个方法的时候,使用空接口作为参数可以变得很有用,因为空接口可以接收任何类型(int, string, []int......)❞InterfacesJordan Oreillic曾这样描述Go语言的in...

weixin_29109261的博客 157

深入理解 Go 语言中的接口(interface)

在 Go 语言中接口(interface)是一种类型,一种抽象的类型接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节实现接口的条件一个对象只要全部实现了接口中的方法,那么就实现了这个接口换句话说,接口就是一个需要实现的方法列表定义了一个 Usber 接口让 Phone 和 Camera 结构体实现这个接口//1、接口是一个规范start()stop()//2.如果接口里面有方法的话,必要通过结构体或通过自定义类型实现这个接口。

MrWangisgoodboy的博客 1625

【Go】P16 Go 语言核心精讲:深入理解接口(interface)

在 Go 语言中,如果说goroutine和channel是其并发的利剑,那么interface(接口)就是 Go 语言实现多态和组件化设计的灵魂。它是一种抽象类型,定义了一组方法的集合,是 Go 语言实现“鸭子类型”的核心。理解接口,是从 Go 入门到精通的必经之路。本文将从基础定义开始,深入探讨空接口、类型断言、接收者区别以及高级用法,助您彻底掌握 Go 接口的精髓。接口的定义使用type关键字和interface关键字,内部是方法签名(方法名、参数列表、返回值列表)的集合。

weixin_43098506的博客 987

深入理解Go语言中的Interface:灵活而强大的类型系统

在Go语言的生态系统中,接口扮演着核心角色。它们通过提供抽象的行为定义,允许开发者声明所需的功能,而不必关心具体的实现细节。这种抽象化方法不仅增强了代码的灵活性和可维护性,而且体现了Go语言所倡导的面向接口编程的理念。

王中阳讲编程 1013

谨慎对待Go语言中对interface的nil判断

谨慎对待Go语言中对interface的nil判断 在进行Go语言编程中,我们会看见诸如if err == nil {}或者if err != nil {}之类的判断,这跟go语言的错误处理哲学(计划失败而非成功 / 及早失败)有关;大多数情况下,我们对一个err是否是nil进行判断是很直白的,无需考虑很多,但是如果对于interface的情况来说,处理的时候稍有点难度,多了许多要留意的地方。 看个重要的例子 package main import ( "bytes" "fmt" "io" ) /

qq_30927019的博客 1026

深入理解Go语言(01): interface源码分析

深入理解Go语言(01): interface源码分析 分析接口的赋值,反射,断言的实现原理 版本:golang v1.12 interface底层使用2个struct表示的:eface和iface 一:接口类型分为2个# 1. 空接口# //比如 var i interface{} 2. 带方法的接口# //比如 type studenter interface { GetName() string GetAge() int } 二:eface 空接口定义# 空接口通过eface

小强的专栏 439

关于go语言的interface(接口)的理解小记 2020.11.2

main.go: package main import "fmt" type Book interface {//定义一个接口,里面有两个方法 fanshu() 和 bishu() fanshu() bishu() } type Book01 struct {//定义一个Book01类型的接口体,里面有一个Name属性(字段) Name string } func (book01 Book01) fanshu(){//代表着book01就是一个Book类型的接口,因为它实现了

lakersssss24的博客 245

golang 结构体断言_Golang中的reflect原理

反射(reflect)是在计算机程序运行时,访问,检查,修改它自身的一种能力,是元编程的一种形式。在Java等语言中都很好地支持了反射。Golang也实现了反射,主要核心位于reflect包,官方文档为:https://golang.org/pkg/reflect/​golang.org本文将主要介绍Golang中的反射原理和支持的反射操作。1. reflect原理:结构体与关系Golang是强类...

weixin_39800387的博客 516
上一篇: 海量数据处理(面试题)
下一篇: golang: string与byte的区别
pg_dog
博客等级 码龄10年 19粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值