当前位置: 首页 > 编程日记 > 正文

【Go】Go基础(九):接口(Interfaces)与反射(reflection)

一、接口(interfaces)
1、概述

接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。接口里也不能包含变量。

通过如下格式定义接口:

type Namer interface {
Method1(param_list) return_type
Method2(param_list) return_type

}

类型不需要显式声明它实现了某个接口:接口被隐式地实现。多个类型可以实现同一个接口。
实现某个接口的类型(除了实现接口方法外)可以有其他的方法。
一个类型可以实现多个接口。
接口类型可以包含一个实例的引用, 该实例的类型实现了此接口(接口是动态类型)。

2、例子:
package mainimport "fmt"type Shaper interface {Area() float32
}type Square struct {side float32
}func (sq *Square) Area() float32 {return sq.side * sq.side
}func main() {sq1 := new(Square)sq1.side = 5var areaIntf ShaperareaIntf = sq1// shorter,without separate declaration:// areaIntf := Shaper(sq1)// or even:// areaIntf := sq1fmt.Printf("The square has area: %f\n", areaIntf.Area())
}

输出:

The square has area: 25.000000

上面的程序定义了一个结构体 Square 和一个接口 Shaper,接口有一个方法 Area()。

3、 接口嵌套

接口嵌套接口
一个接口可以包含一个或多个其他的接口,这相当于直接将这些内嵌接口的方法列举在外层接口中一样。

比如接口 File 包含了 ReadWrite 和 Lock 的所有方法,它还额外有一个 Close() 方法。

type ReadWrite interface {Read(b Buffer) boolWrite(b Buffer) bool
}type Lock interface {Lock()Unlock()
}type File interface {ReadWriteLockClose()
}
4、 类型断言:如何检测和转换接口变量的类型
if v, ok := varI.(T); ok {  // checked type assertionProcess(v)return
}if _, ok := varI.(T); ok {// ...
}

varI 必须是一个接口变量,否则编译器会报错:invalid type assertion: varI.(T) (non-interface type (type of varI) on left)

5、 类型判断:type-switch
switch t := areaIntf.(type) {
case *Square:fmt.Printf("Type Square %T with value %v\n", t, t)
case *Circle:fmt.Printf("Type Circle %T with value %v\n", t, t)
case nil:fmt.Printf("nil value: nothing to check?\n")
default:fmt.Printf("Unexpected type %T\n", t)
}//仅仅是测试变量的类型,不用它的值,那么就可以不需要赋值语句,比如:switch areaIntf.(type) {
case *Square:// TODO
case *Circle:// TODO
...
default:// TODO
}
6、 测试一个值是否实现了某个接口

假定 v 是一个值,然后我们想测试它是否实现了 Stringer 接口,可以这样做:

type Stringer interface {String() string
}if sv, ok := v.(Stringer); ok {fmt.Printf("v implements String(): %s\n", sv.String()) // note: sv, not v
}
7、使用方法集与接口

总结

在接口上调用方法时,必须有和方法定义时相同的接收者类型或者是可以从具体类型 P 直接可以辨识的:

指针方法可以通过指针调用
值方法可以通过值调用
接收者是值的方法可以通过指针调用,因为指针会首先被解引用
接收者是指针的方法不可以通过值调用,因为存储在接口中的值没有地址
将一个值赋值给一个接口时,编译器会确保所有可能的接口方法都可以在此值上被调用,
因此不正确的赋值在编译期就会失败。

Go 语言规范定义了接口方法集的调用规则:

类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
类型 T 的可调用方法集包含接受者为 T 的所有方法
类型 T 的可调用方法集不包含接受者为 *T 的方法
8、空接口
type Any interface {}

通过空接口测试变量类型

package mainimport "fmt"type specialString stringvar whatIsThis specialString = "hello"func TypeSwitch() {testFunc := func(any interface{}) {switch v := any.(type) {case bool:fmt.Printf("any %v is a bool type", v)case int:fmt.Printf("any %v is an int type", v)case float32:fmt.Printf("any %v is a float32 type", v)case string:fmt.Printf("any %v is a string type", v)case specialString:fmt.Printf("any %v is a special String!", v)default:fmt.Println("unknown type!")}}testFunc(whatIsThis)
}func main() {TypeSwitch()
}

输出:

any hello is a special String!
二、反射包 reflect

反射是用程序检查其所拥有的结构,尤其是类型的一种能力;这是元编程的一种形式。反射可以在运行时检查类型和变量,例如它的大小、方法和 动态 的调用这些方法。
reflect.TypeOf 和 reflect.ValueOf,返回被检查对象的类型和值。

Kind():反射可以从接口值反射到对象,也可以从对象反射回接口值。

v:=reflect.ValueOf(x),那么 v.Kind() 返回 reflect.Float64
Kind 总是返回底层类型:
type MyInt int
var m MyInt = 5
v := reflect.ValueOf(m)
方法 v.Kind() 返回 reflect.Int。
CanSet():
Elem():
SetFloat():
有些时候需要反射一个结构类型。NumField() 方法返回结构内的字段数量;通过一个 for 循环用索引取得每个字段的值 Field(i)。

空接口和函数重载
在 Go 语言中函数重载可以用可变参数 …T 作为函数最后一个参数来实现。
如果我们把 T 换为空接口,那么可以知道任何类型的变量都是满足 T (空接口)类型的,这样就允许我们传递任何数量任何类型的参数给函数,即重载的实际含义。

函数 fmt.Printf 就是这样做的:

fmt.Printf(format string, a ...interface{}) (n int, errno error)
三、总结:Go 中的面向对象

我们总结一下前面看到的:Go 没有类,而是松耦合的类型、方法对接口的实现。
OO 语言最重要的三个方面分别是:封装,继承和多态,在 Go 中它们是怎样表现的呢?
封装(数据隐藏):和别的 OO 语言有 4 个或更多的访问层次相比,Go 把它简化为了 2 层:

1)包范围内的:通过标识符首字母小写,对象 只在它所在的包内可见
2)可导出的:通过标识符首字母大写,对象 对所在包以外也可见

类型只拥有自己所在包中定义的方法。

继承:用组合实现:内嵌一个(或多个)包含想要的行为(字段和方法)的类型;多重继承可以通过内嵌多个类型实现
多态:用接口实现:某个类型的实例可以赋给它所实现的任意接口类型的变量。类型和接口是松耦合的,并且多重继承可以通过实现多个接口实现。Go 接口不是 Java 和 C# 接口的变体,而且接口间是不相关的,并且是大规模编程和可适应的演进型设计的关键。

相关文章:

用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用原型链和EventTrigger

原型链是JS的必备,作为ECMAScript4,原型链也是支持的。 特别说明,ActionScript3是支持完整的面向对象继承支持的,原型链只在某些非常特殊的情况下使用。 本文旨在介绍如何使用原型链。 任意对象类型都有一个prototype属性,包括导入的Unity的A…

教育部发文35所高校新增AI本科专业!想回去重新高考

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」7折优惠最后3天,请扫码咨询 ↑↑↑作者 | 琥珀出品 | AI科技大本营(ID:rgznai100)2019 年 3 月 28 日,教育部公布了 2018 年度普通高等学校本科专业备案和审批结果。消息一出&…

莱芜市公安局交警支队智能交通项目集成及容灾公开招标公告

莱芜市公安局交警支队智能交通建设项目公开招标公告 时间:2011-7-5 点击:249莱芜市公安局交警支队智能交通建设项目公开招标公告一、招标人名称:莱芜市公安局交警支队 联系方式:0634-5667998(吕老师)二、招标代理机构名称&#x…

【Go】Go基础(十):文件读写

一、读写数据 1、读取用户的输入 使用fmt 包提供的 Scan 和 Sscan 开头的函数; * Scanln 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。 * Scanf 与其类似,除了 Scanf 的第一个参数用作格式字符…

怎样能拿到第一份编程工作?这里告诉你答案 | 码书

“写代码时,每次都要告诉自己:最后负责维护代码的,会是一个知道你住在哪的变态暴力狂。” ——约翰伍德(John Woods)拿下第一份编程工作需要付出更多努力,但是如果采纳下面的建议,应该不会有太大…

JSON知识点

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读…

asp常用函数(备忘)

1.数组长度&#xff1a; <% Dim grade,i gradesplit("1,2,5,10,20,50,100,200,500,1000",",") for i0 to ubound(grade) response.write grade(i)&"\n" next %> 2.获得插入的id set rs server.createobject(&q…

【leetcode】力扣刷题(1):两数之和(Go、Python)

一、问题描述 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;你不能重复利用这个数组中同样的元素。 示例: 给定 nums [2, 7,…

轻松练:如何从900万张图片中对600类照片进行分类|技术头条

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」7折优惠最后2天&#xff0c;请扫码咨询 ↑↑↑作者 | Aleksey Bilogur译者 | 风车云马责编 | Jane出品 | AI科技大本营&#xff08;公众号id:rgznai100&#xff09;【导语】完成一个简单的端到端的机器学习模型需要几步&…

介绍两个好玩的和Github相关的Chrome扩展

1. Octotree 默认的github网页里的代码显示没有我们在IDE里看到的直观&#xff0c;即代码文件所在的文件夹无法以树形层级结构显示在屏幕左边。 安装Octotree之后&#xff1a; 方便多了。 2. Isometric Contributions github commit的统计页面比较平淡&#xff1a; 安装了Isome…

Schema约束模式实例

book.xsd <?xml version"1.0" encoding"UTF-8"?> <!-- xmlns:默认命名空间 xmlns:xs:当前的文档的标记来自http://www.w3.org/2001/XMLSchema命名空间 前缀:xs elementFormDefault&#xff1a;当前文档使用的标记必须是使用http://www.w3.…

【leetcode】力扣刷题(2):两数相加(go语言)

一、问题描述 给出两个 非空 的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照 逆序 的方式存储的&#xff0c;并且它们的每个节点只能存储 一位 数字。 如果&#xff0c;我们将这两个数相加起来&#xff0c;则会返回一个新的链表来表示它们的和。 您可…

“GANs之父”Ian Goodfellow被爆已从Google离职

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」7折优惠最后2天&#xff0c;请扫码咨询 ↑↑↑整理 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;3 月 28 日&#xff0c;深度学习大牛李沐在知乎爆料称&#xff0c;他从某机器学习大佬处获悉&#xff0c…

Gulp快速入门教程

Gulp是基于流的前端自动化的构建工具&#xff0c;虽说如今是webpack盛行的时代&#xff0c;但是gulp和webpack整合效果更美味的&#xff0c;鱼与熊掌都可兼得哦&#xff01;本文只介绍下Gulp的基本使用和一些常用的Gulp插件&#xff0c;废话不多说&#xff0c;一起来看看吧。 g…

linux 防火墙 命令

-- 永久设置防火墙&#xff08;重启不恢复&#xff09; 开启&#xff1a;chkconfig iptables on 关闭&#xff1a;chkconfig iptables off-- 暂时设置防火墙&#xff08;重启后恢复&#xff09; 开启&#xff1a;service iptables start 关闭&#xff1a;service i…

如何将TensorFlow Serving的性能提高超过70%?

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」7折优惠最后2天&#xff0c;请扫码咨询 ↑↑↑译者 | Major出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;TensorFlow已经发展成为事实上的ML(机器学习)平台&#xff0c;在业界和研究领域都很流行。对TensorFlow…

【leetcode】力扣刷题(3):无重复字符的最长子串(go语言)

一、问题描述 给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是…

单点登录与权限管理本质:session和cookie介绍

本篇开始写「单点登录与权限管理」系列的第一部分&#xff1a;单点登录与权限管理本质&#xff0c;这部分主要介绍相关的知识概念、抽象的处理过程、常见的实现框架。通过这部分的介绍&#xff0c;能够对单点登录与权限管理有整体上的了解&#xff0c;对其相关概念、处理流程、…

【.Net MF网络开发板研究-04】Socket编程之服务端

前几篇文章介绍了Http相关的应用&#xff0c;其实从技术角度而言&#xff0c;应该先介绍Socket编程&#xff0c;然后再介绍Http&#xff0c;毕竟Http是用Socket相关函数编程实现的。 .NET Micro Framework的Socket函数和桌面版.NET Framework中的函数完全兼容&#xff0c;换句话…

【Qt】Qt中调用python接口

在Qt程序中调用python函数从步骤 1、在pro中添加python的头文件路径和库 INCLUDEPATH += /usr/include/python3.4 LIBS += -L /usr/lib/python3.4/config-3.4m-x86_64-linux-gnu -lpython3.42、添加python头文件 #undef slots #include <python3.4/Python.h> #define …

优雅的理解 call 和 apply 的使用方法

作者在看到一篇优雅的使用 js 的各种方法解决算法的时候产生的疑问&#xff0c;到底什么时候使用 apply 和 call 啦&#xff1f; 每次看到别人用 apply 和 call 其实从以前的懵懵懂懂到现在的明白&#xff0c;但是自己从来未下手去用过&#xff0c;最近比较闲。开始打一下 Jav…

何恺明等人提TensorMask框架:比肩Mask R-CNN,4D张量预测新突破

整理 | 刘畅、Jane 责编 | Jane 出品 | AI科技大本营&#xff08;id&#xff1a;rgznai100) 看到今天要给大家介绍的论文&#xff0c;也许现在大家已经非常熟悉 Ross Girshic、Piotr Dollr 还有我们的大神何恺明的三人组了。没错&#xff0c;今天这篇重磅新作还是他们的产出&am…

init.rc的disabled含义

http://www.kandroid.org/android_pdk/bring_up.htmlhttp://androidnote.com/Article_show.asp?ArticleID649如果该服务选项中没有disabled定义&#xff0c;则在init.rc中解析到这个服务的时候&#xff0c;会马上执行这个服务。而如果在服务的选项中增加了disabled定义&#x…

【Qt】在ubuntu14.04上安装Qt5.12(失败)

注意 在ubuntu14.04上安装Qt5.12最终失败了,Qt5.12需要的libdbus库的版本和ubuntu14.04中的不一致,如果强行升级libdbus库版本,会导致系统桌面无法启动。 再次提示:不要按照下述步骤操作,它只是一个记录失败操作的笔记。 如果有大神安装成功了,还请不吝赐教。 1、安装Q…

80+机器学习数据集,还不快收藏

整理 | suiling 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 对于从事机器学习的小伙伴来说&#xff0c;机器学习必须以大量的数据为基础&#xff0c;否则构建再好的模型也不能达到你想要的效果。同时&#xff0c;不同质量的数据集也会影响到模型训练的效果。之…

SpringBoot+Docker+Git+Jenkins实现简易的持续集成和持续部署

前言 本篇文章引导你使用Jenkins部署[SpringBoot项目],同时使用Docker和Git实现简单的持续集成和持续部署。&#xff08;项目地址&#xff1a;sso-merryyou&#xff09; 流程图如下&#xff1a; push代码到Github触发WebHook。&#xff08;因网络原因&#xff0c;本篇使用gitee…

LINUX下用C语言历遍目录 C语言列出目录

&#xff08;被考了一题遍历目录&#xff0c;连需要的系统库函数我都不知道...打击中...&#xff09;小羽给了一个答案&#xff1a;#include<stdio.h> #include<dirent.h>int main(int argc,char **argv) { DIR *p; struct dirent *dirp; if (argc ! 2) …

【linux】ubuntu14.04升级dbus到1.13.8,杯具了,无法进入桌面

一、问题描述 在ubuntu14.04中安装了Qt5.12&#xff0c;启动QtCreator报错&#xff0c;需要高版本的dbus。 将dbus升级到1.13.8后&#xff0c;杯具了&#xff0c;无法进入桌面 二、尝试解决 1、尝试恢复之前的版本&#xff08;失败&#xff09; 进入终端界面&#xff1a;Ct…

线下教育地位遭冲击?“AI+教育”公司同台讲了这些事实

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」7折优惠最后1天&#xff0c;请扫码咨询 ↑↑↑整理 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;近日&#xff0c;网易新闻、网易有道、清华大学数据科学研究院在清华大学举办了“中国AI创新者论坛”。当…

mysql查看正在执行的sql语句

有2个方法&#xff1a; 1、使用processlist&#xff0c;但是有个弊端&#xff0c;就是只能查看正在执行的sql语句&#xff0c;对应历史记录&#xff0c;查看不到。好处是不用设置&#xff0c;不会保存。 -- use information_schema; -- show processlist; 或者&#xff1a; -- …