首页 > 编程语言 >GO语言中面向接口编程

GO语言中面向接口编程

时间:2023-10-16 10:12:38浏览次数:28  
标签:int car 编程 接口 interface GO Transporter type

接口的基本概念

接口是一组行为规范的集合。

type Transporter interface { //定义接口。通常接口名以er结尾
    //接口里面只定义方法,不定义变量
    move(src string, dest string) (int, error) //方法名 (参数列表) 返回值列表
    whistle(int) int //参数列表和返回值列表里的变量名可以省略
}

只要结构体拥有接口里声明的所有方法,就称该结构体实现了接口

一个struct可以同时实现多个接口。

type Car struct { //定义结构体时无需要显式声明它要实现什么接口
    price int
}

func (car Car) move(src string, dest string) (int, error) {
    return car.price, nil
}
func (car Car) whistle(n int) int {
    return n
}

接口值有两部分组成, 一个指向该接口的具体类型的指针和另外一个指向该具体类型真实数据的指针。

car := Car{"宝马", 100}
var transporter Transporter
transporter = car

接口的使用

func transport(src, dest string, transporter Transporter) error {
	 _,err := transporter.move(src, dest)
	return err
}
var car Car		//Car实现了Transporter接口
var ship Shiper	// Shiper实现了Transporter接口
transport("北京", "天津", car)
transport("北京", "天津", ship)

接口的赋值

如果是指针实现了方法,那只能给接口赋值指针

如果是值实现了方法,那可以给接口赋值指针,也可以赋值值

func (car Car) whistle(n int) int {…}//方法接收者是值
func (ship *Shiper) whistle(n int) int {…} //方法接收者用指针,则实现接口的是指针类型
car := Car{}
ship := Shiper{}
var transporter Transporter
transporter = car 
transporter = &car     //值实现的方法,指针同样也实现了
transporter = &ship

接口嵌入

将被嵌入的接口,继承嵌入接口的所有方法

type Transporter interface {
	whistle(int) int
}
type Steamer interface {
    Transporter //接口嵌入。相当于Transporter接口定义的行为集合是Steamer的子集
    displacement() int
}

空接口

空接口类型用interface{}表示,注意有{}

var i interface{} 

在go中any也是空接口

源码

type any = interface{}

空接口没有定义任何方法,因此任意类型都实现了空接口。

var a int = 5
i = a
func square(x interface{}){} //该函数可以接收任意数据类型

slice的元素、map的key和value都可以是空接口类型。

map中的key可以是任意能够用==操作符比较的类型,不能是函数、map、切片,以及包含上述3中类型成员变量的的struct。

map的value可以是任意类型。

类型断言

if v, ok := i.(int); ok {//若断言成功,则ok为true,v是具体的类型   如果断言失败,v就是个空的
	fmt.Printf("i是int类型,其值为%d\n", v)
}else if v, ok := i.(string); ok{
    fmt.Printf("i是string类型,其值为%s\n", v)
}else {
	fmt.Println("i不是int和string类型")
}

当要判断的类型比较多时,就需要写很多if-else,更好的方法是使用switch i.(type)

switch v := i.(type) {    //隐式地在每个case中声明了一个变量v
case int:  //v已被转为int类型
	fmt.Printf("ele is int, value is %d\n", v)
	//在 Type Switch 语句的 case 子句中不能使用fallthrough
case float64:      //v已被转为float64类型
	fmt.Printf("ele is float64, value is %f\n", v)
case int8, int32, byte: //如果case后面跟多种type,则v还是interface{}类型
	fmt.Printf("ele is %T, value is %d\n", v, v)
}

面向接口编程

电商推荐流程

为每一个步骤定义一个接口。

type Recaller interface {
    Recall(n int) []*common.Product //生成一批推荐候选集
}
type Sorter interface {
    Sort([]*common.Product) []*common.Product //传入一批商品,返回排序之后的商品
}
type Filter interface {
    Filter([]*common.Product) []*common.Product //传入一批商品,返回过滤之后的商品
}
type Recommender struct {
    Recallers []recall.Recaller
    Sorter sort.Sorter
    Filters []filter.Filter
}

使用纯接口编写推荐主流程。

func (rec *Recommender) Rec() []*common.Product {
	RecallMap := make(map[int]*common.Product, 100)
	//顺序执行多路召回
	for _, recaller := range rec.Recallers {
		products := recaller.Recall(10) //统一设置每路最多召回10个商品
		for _, product := range products {
			RecallMap[product.Id] = product //把多路召回的结果放到map里,按Id进行排重
		}
	}
	//把map转成slice
	RecallSlice := make([]*common.Product, 0, len(RecallMap))
	for _, product := range RecallMap {
		RecallSlice = append(RecallSlice, product)
	}
	SortedResult := rec.Sorter.Sort(RecallSlice) //对召回的结果进行排序
	//顺序执行多种过滤规则
	FilteredResult := SortedResult
	for _, filter := range rec.Filters {
		FilteredResult = filter.Filter(FilteredResult)
	}
	return FilteredResult
}

面向接口编程,在框架层面全是接口。

具体的实现由不同的开发者去完成,每种实现单独放到一个go文件里,大家的代码互不干扰。

通过配置选择采用哪种实现,也方便进行效果对比。

校验是否实现接口

定义接口

// user模块中定义的接口
type Server interface {
	DeleteUser(ctx context.Context, in *DeleteUserRequest) (*User, error)
}

实现接口

type implServer struct {
}

校验接口

var _ user.Server = (*implServer)(nil)

这么做的目的是让IDE能够提示咱们,是否实现了对应的接口,非常方便

标签:int,car,编程,接口,interface,GO,Transporter,type
From: https://www.cnblogs.com/guangdelw/p/17766762.html

相关文章

  • 轻松掌握组件启动之MongoDB(上):高可用复制集架构环境搭建
    MongoDB复制集复制集架构在生产环境中,强烈不建议使用单机版的MongoDB服务器。原因如下:单机版的MongoDB无法保证系统的可靠性。一旦进程发生故障或是服务器宕机,业务将直接不可用。此外,一旦服务器上的磁盘损坏,数据会直接丢失,而此时并没有任何副本可用。为了确保数据的高可用性和......
  • GO语言中的函数
    函数的基本形式//函数定义。a,b是形参funcargf(aint,bint){ a=a+b}varx,yint=3,6argf(x,y)//函数调用。x,y是实参形参是函数内部的局部变量,实参的值会拷贝给形参。函数定义时的第一个的大括号不能另起一行。形参可以有0个或多个。参数类型相同时可......
  • 多线程编程同步:互斥锁和条件变量
    多线程同步怎样同步多个线程或多个进程的活动?为允许在线程或进程间共享数据,同步通常是必需的。而互斥锁和条件变量是同步的基本组成部分。互斥锁用于保护临界区(criticalregion),以保证任何时刻只有一个线程在执行其中的代码,或者任何时刻只有一个进程在执行其中的代码。互斥......
  • 树叶识别系统python+Django网页界面+TensorFlow+算法模型+数据集+图像识别分类
    一、介绍树叶识别系统。使用Python作为主要编程语言开发,通过收集常见的6中树叶('广玉兰','杜鹃','梧桐','樟叶','芭蕉','银杏')图片作为数据集,然后使用TensorFlow搭建ResNet50算法网络模型,通过对数据集进行处理后进行模型迭代训练,得到一个识别精度较高的H5模型文件。并基于Dja......
  • ARC167D Good Permutation 题解
    题意给定一个长度为\(N\)的排列\((P_1,P_2,\cdots,P_N)\)。称一个排列\(P\)为“好排列”当且仅当对于所有\(1\leqx\leqN\),都能通过不停地使\(x\leftarrowP_x\)将\(x\)变成\(1\)。通过最小次数操作将\(P\)变成“好排列”,每次操作为交换\(P\)中的两个数\(P_i\)......
  • 为什么Google在JSON响应中添加了`while(1);`?
    内容来自DOChttps://q.houxu6.top/?s=为什么Google在JSON响应中添加了while(1);?为什么Google在(私有)JSON响应前加上while(1);?例如,这是在Google日历中打开和关闭日历时的响应:while(1);[['u',[['smsSentFlag','false'],['hideInvitations','false......
  • mongoDB​二
    MongoDB中的索引索引就是为了加速查询的,MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧。下面是创建索引的命令:创建索引:db.集合名称.ensureIndex({"name":1})1代表索引升序存储-1代表索引降序存储_id默认自动创建索引注意:该索引被创建后,基......
  • golang值接收者与指针接收者(一)
    golang方法的接收者有两种:值接收者与指针接收者。平时使用中两种接收者的主要区别就是能不能修改接收者的内部值。先说结论:值接收者方法不能修改结构体内部的值,指针接收者方法可以修改结构体内部的值。做个测试:typeStudentstruct{ ageint}func(sStudent)SetAge(ag......
  • 关于django中间件执行过程
    众所周知,django的中间件一般有五个方法,常用的仅三个,示例如下fromdjango.utils.deprecationimportMiddlewareMixinfromdjango.httpimportHttpResponse中间件示例classMyMiddleWare(MiddlewareMixin): defprocess_request(self,request): pass defprocess_view(se......
  • Go 匿名函数与闭包
    Go匿名函数与闭包匿名函数和闭包是一些编程语言中的重要概念,它们在Go语言中也有重要的应用。让我们来详细介绍这两个概念,并提供示例代码来帮助理解。目录Go匿名函数与闭包一、匿名函数(AnonymousFunction)二、闭包函数(Closure)一、匿名函数(AnonymousFunction)匿名函数,也称为无......