go 定义接口解决 import cycle not allowed
前言
go项目运行报错: import cycle not allowed,导入循环(import cycle)
报错原因,在Go语言中,两个或更多的包之间形成了相互依赖的关系,即A包导入了B包,而B包又反过来导入了A包,形成一个循环。
这种循环会导致编译器无法确定每个包的完整依赖图,因为它们互相引用,就像一个无解的链条。
避免导入循环的关键在于理解包的依赖结构。一般来说,应该尽量保持单向依赖,也就是说,一个包不应该直接或间接地导入其自身,也不应形成一个闭合的循环。
在代码中,可以通过接口类型的变量来使用这些包,而不是直接使用具体的包。
这样你的代码不再依赖于具体的包,而是依赖于接口。
举例一
假设有两个包 pkgA 和 pkgB,它们需要相互调用对方的功能。我们将通过引入接口来避免循环依赖。
代码示例
文件结构
/project
├── main.go
├── pkgA
│ └── pkgA.go
└── pkgB
└── pkgB.go
pkgA.go
// pkgA/pkgA.go
package pkgA
// 定义一个接口
type BInterface interface {
PerformB()
}
// 包A的一个功能
func PerformA(b BInterface) {
// 调用包B的功能
b.PerformB()
}
pkgB.go
// pkgB/pkgB.go
package pkgB
import "example/pkgA"
// 实现包A定义的接口
type StructB struct{}
// 实现PerformB方法
func (b StructB) PerformB() {
// 包B的具体实现
println("Performing B")
}
// 包B的一个功能
func CallA() {
// 使用包A的功能
pkgA.PerformA(StructB{})
}
main.go
// main.go
package main
import "example/pkgB"
func main() {
// 调用包B的功能
pkgB.CallA()
}
代码解析
定义接口:在
pkgA中定义一个接口BInterface,该接口包含一个方法PerformB()。这个接口的目的是让pkgA不需要直接依赖pkgB,而是依赖于接口。实现接口:在
pkgB中定义一个结构体StructB,并实现PerformB()方法。这样,pkgB可以在需要调用pkgA的功能时,通过接口传递自身的实例。使用功能:在
pkgB的CallA()方法中,调用pkgA的PerformA()方法,并传入StructB的实例。这样,pkgA就可以通过接口调用pkgB的功能,而不需要直接依赖于pkgB。主函数:在
main.go中,调用pkgB的CallA()方法,启动整个流程。
运行结果
当运行 main.go 时,输出将会是:
Performing B
通过引入接口 BInterface,我们成功地解耦了 pkgA 和 pkgB,避免了循环依赖的问题。这种设计使得代码更加灵活和可维护。
举例二
模拟一个简单的支付系统,其中有两个包:payment 和 notification。
场景描述
payment包负责处理支付逻辑。notification包负责发送通知(例如,支付成功的通知)。
我们将通过接口来解耦这两个包,以避免循环依赖。
文件结构
/project
├── main.go
├── payment
│ └── payment.go
└── notification
└── notification.go
payment.go
// payment/payment.go
package payment
import "example/notification"
// 定义一个接口
type Notifier interface {
SendNotification(message string)
}
// 支付处理函数
func ProcessPayment(amount float64, notifier Notifier) {
// 处理支付逻辑(简化)
if amount > 0 {
// 支付成功,发送通知
notifier.SendNotification("Payment of $" + fmt.Sprintf("%.2f", amount) + " was successful.")
}
}
notification.go
// notification/notification.go
package notification
import "fmt"
// 实现包 payment 的 Notifier 接口
type EmailNotifier struct{}
// 实现 SendNotification 方法
func (e EmailNotifier) SendNotification(message string) {
fmt.Println("Email Notification:", message)
}
// 实现一个其他的通知方式(例如 SMS)
type SMSNotifier struct{}
// 实现 SendNotification 方法
func (s SMSNotifier) SendNotification(message string) {
fmt.Println("SMS Notification:", message)
}
main.go
// main.go
package main
import (
"example/notification"
"example/payment"
)
func main() {
emailNotifier := notification.EmailNotifier{}
smsNotifier := notification.SMSNotifier{}
// 使用 EmailNotifier 发送通知
payment.ProcessPayment(100.0, emailNotifier)
// 使用 SMSNotifier 发送通知
payment.ProcessPayment(50.0, smsNotifier)
}
代码解析
- 定义接口:在
payment包中,定义了一个接口Notifier,包含一个方法SendNotification(message string)。这个接口的目的是让payment包不直接依赖于notification包,而是依赖于一个抽象的通知接口。 - 支付处理:在
payment包中,ProcessPayment函数负责处理支付逻辑,并在支付成功时调用notifier.SendNotification()方法。这里的notifier参数是Notifier接口的实现。 - 实现通知:在
notification包中,定义了两个结构体EmailNotifier和SMSNotifier,它们都实现了Notifier接口的SendNotification方法。 - 主函数:在
main.go中,我们创建了EmailNotifier和SMSNotifier的实例,并将它们传递给ProcessPayment函数。这样,支付处理逻辑可以根据不同的实现发送通知。
运行结果
当运行 main.go 时,输出将会是:
Email Notification: Payment of $100.00 was successful.
SMS Notification: Payment of $50.00 was successful.
通过引入接口 Notifier,成功地解耦了 payment 和 notification 包。这样,payment 包不需要知道 notification 包的具体实现,只需要依赖于接口。这种设计使得系统更加灵活,便于扩展和维护。
go 定义接口解决 import cycle not allowed的更多相关文章
- go 报错 import cycle not allowed
运行时报错,import cycle not allowed : 查了goole大概知道了原因,还是导包类的问题,我检察了一下我的代码库,发现我昨天划分几个工具文件,里面的两个文件相互引用,就导致报i ...
- import cycle not allowed in test
写个 sdk 的测试时报错 import cycle not allowed in test 后发现因为测试文件内多写了导入同包路径. 同 package 下的 xxx_test.go 内不需要额外 ...
- linux系统:go build报错import cycle not allowed
go build 困扰我多时的 go 编译报错:循环导入,代码肯定是没问题的,网上查说重新安装go 我觉得也不是太好的办法 import cycle not allowed package day01 ...
- go环境import cycle not allowed问题处理
1.前言 今天在搭建Go语言环境,从https://golang.org/dl/上下载一个Go语言环境.环境变量配置刚开始如下配置: GOROOT=/home/go/bin go执行文件目录 ...
- python定义接口继承类invalid syntax解决办法
class s_all(metaclass=abc.ABCMeta): #python2.7用此方法定义接口继承 # __metaclass__ = abc.ABCMeta @abc.abstract ...
- python定义接口继承类
zxq547 python定义接口继承类invalid syntax解决办法 1 2 3 4 5 6 7 class s_all(metaclass=abc.ABCMeta): #python ...
- struts2 在拦截器进行注入(依据Action是否实现自己定义接口)
比如:经常在Action中都须要获取当前登录的User,就须要获取Session.然后从Session获取当前登录的User,由于这些步骤都是反复操作,能够想办法在拦截器中进行实现.能够自己定义一个接 ...
- 用关键字interface定义接口,通过关键字implements来实现接口
[定义]Java中,能够完成特定功能的,由若干属性和方法组织成的,相对独立的属性和方法的集合. [用途]实现类的多继承,以解决Java只能单继承,不支持多继承的问题. [特点] 用关键字interfa ...
- go定义接口以及类怎么使用接口
go定义接口以及类怎么使用接口 多态是指代码可以根据类型的具体实现采取不同行为的能力.如果一个类型实现了某个接口,所有使用这个接口的地方,都可以支持这种类型的值. 接口是用来定义行为的类型.这些被定义 ...
- JAVA定义接口格式:
[public]interface 接口名称 [extends父接口名列表] { //静态常量 [public] [static] [final] 数据类型变量名=常量值; //抽象方法 [publi ...
随机推荐
- 开源架构Fabric、FISCO BCOS(以下简称“BCOS”)、CITA 技术对比
转自 https://www.coingogo.com/news/41300 联盟链技术哪家强?开源架构Fabric.FISCO BCOS(以下简称"BCOS").CITA 技术对 ...
- 龙哥量化:通达信分时均线在5分钟K线图上显示
代写技术指标.量化策略,微信:Long622889 龙哥QQ:591438821 T1:=DAY<>REF(DAY,1);T2:=BARSLAST(T1)+1;JX:SUM(AMO,T2) ...
- Qt编写视频监控系统74-悬浮工具栏(半透明/上下左右位置/自定义按钮)
一.前言 在监控系统中一般在视频实时预览的时候,希望提供一个悬浮工具条,可以显示一些提示信息比如分辨率.码率.帧率,提供一堆快捷操作按钮,可以录像.抓拍.云台控制.关闭等操作,参考了国内很多监控厂商客 ...
- Qt编写地图综合应用42-离线轮廓图
一.前言 离线轮廓图使用起来,就没有在线轮廓图方便了,在线的可以直接传入名称拿到,离线的只能自己绘制了,一般需要用区域轮廓图下载器将你需要的区域下载好对应的js文件,其实就是一堆坐标点集合数组,这些数 ...
- 如何在众多Ubuntu版本中挑选出最适配自身需求的系统版本?用德承工控机GM-1100来深度剖析其中的门道
Ubuntu是一款基于Debian GNU/Linux,支持x86.amd64(x64)和ppc架构,以桌面应用为主的Linux操作系统.其名称来自非洲南部的语言"ubuntu"( ...
- MySql 建表出现的问题 : [ERR] 1064 - You have an error in your SQL syntax; check the manual.......
使用 MySql 建表出现的问题 在使用 Navicat Premium 运行 sql 语句进行建表时,MySQL 报错如下: 1064 - You have an error in your SQL ...
- 移动端开源 IM 框架 MobileIMSDK v6.0 发布!
一.更新内容简介 本次为主要版本更新(本次更新内容见文末"MobileIMSDK v6.0更新内容 "一节),强势升级,将同时支持TCP.UDP.WebSocket三种协议,精心封 ...
- spark (六) RDD算子(operator)
目录 1 转换算子(transformer)(将旧的RDD包装成新RDD) 1.1 单值类型 1.1.1 map 1.1.2 mapPartition 1.1.3 mapPartitionsWithI ...
- WPF使用Microsoft.Toolkit.Mvvm作为Mvvm框架DryIoc作依赖注入
背景 MVVMLight已多年未更新,Microsoft.Toolkit.Mvvm作为MVVMLight继任者,需要学习一下. Microsoft.Toolkit.Mvvm跟MVVMLight使用非常 ...
- 创建Windows service使用FluentScheduler定时刷新网页
我们都知道iis的程序池默认的闲置回收时间是20分钟, 如果是自己的服务器,我们可以设置成0,闲置不回收. 这样网站就不会出现每隔20分钟没有访客访问就出现打开非常慢的情况. 但是,如果个别网站不是用 ...