Gone v2 如何解决Goner间的循环依赖问题

从零开始学习 Go 1.25 编程 今天是你新生活的第一天,无论年龄、背景如何,改变从这一刻开始。CodeGym帮助成千上万普通人转型为程序员,从零基础到掌握Go语言,完成真实项目,甚至入职心仪岗位。Go语言简洁高效,适合服务器端开发,是云基础设施、微服务和高负载系统的首选。2026年正是入行良机,你的经验反而是优势。别犹豫,迈出第一步,你将收获技能、自信与全新人生。🚀 阅读详情

项目地址:https://github.com/gone-io/gone

原文地址:https://github.com/gone-io/gone/blob/v2.0.3/docs/circular_dependency.md

引例

先来看两个测试用例:

  • 用例1:
type depA1 struct {
	gone.Flag
	dep *depB1 `gone:"*"`
}

type depB1 struct {
	gone.Flag
	dep *depA1 `gone:"*"`
}

func TestCircularDependency1(t *testing.T) {
	gone.
		NewApp().
		Load(&depA1{}).
		Load(&depB1{}).
		Run()
}
  • 用例2:

type dep1 struct {
	gone.Flag
	dep *dep2 `gone:"*"`
}

func (d *dep1) Init() {}

type dep2 struct {
	gone.Flag
	dep *dep1 `gone:"*"`
}

func (d *dep2) Init() {}

func TestCircularDependency2(t *testing.T) {
	gone.
		NewApp().
		Load(&dep1{}).
		Load(&dep2{}).
		Run()
}
  • 用例3:
type depA3 struct {
	gone.Flag
	dep *depB3 `gone:"*"`
}
type depB3 struct {
	gone.Flag
	dep *depA3 `gone:"*"`
}

func (d *depB3) Init() {}

func TestCircularDependency3(t *testing.T) {
	gone.
		NewApp().
		Load(&depA3{}).
		Load(&depB3{}).
		Run()
}

测试结果:

  • 用例1,正常;
  • 用例2,panic,输出:
=== RUN   TestCircularDependency2
--- FAIL: TestCircularDependency2 (0.00s)
panic: GoneError(code=1003); circular dependency:
			<fill fields of "*github.com/gone-io/gone/v2/use_case.dep1"> depend on
				<initialize of "*github.com/gone-io/gone/v2/use_case.dep2"> depend on
					<fill fields of "*github.com/gone-io/gone/v2/use_case.dep2"> depend on
						<initialize of "*github.com/gone-io/gone/v2/use_case.dep1"> depend on
							<fill fields of "*github.com/gone-io/gone/v2/use_case.dep1">

	github.com/gone-io/gone/v2.circularDepsError({0x1400017c280?, 0x14000117a40?, 0x102c3e45a?})
		/Users/jim/works/gone-io/gone/dep.go:21 +0x1e8
	github.com/gone-io/gone/v2.(*Core).Check(0x14000138730)
		/Users/jim/works/gone-io/gone/core.go:204 +0x70
	...
  • 用例3,正常

在3个用例中,都是两个struct相互依赖,但是却只有"用例2"抛出了循环依赖的错误, 为什么呢?


循环依赖分析

Gone框架的初始化流程

Gone框架的初始化流程主要分为两个阶段:

  1. fillAction(字段填充):框架将依赖注入到组件的字段中
  2. initAction(组件初始化):框架调用组件的Init()方法进行初始化

这两个阶段在框架内部被表示为不同的actionType常量:

const (
	fillAction actionType = 1
	initAction actionType = 2
)

组件类型与依赖收集

Gone框架中的组件可以分为几种类型,其中与我们的例子相关的有:

  1. 普通Goner:只嵌入了gone.Flag的结构体,没有实现特殊接口

    • 只需要进行字段填充(fillAction)
    • 不会被标记为needInitBeforeUse
  2. Init Goner:实现了Initiator或InitiatorNoError接口的组件(有Init()方法)

    • 需要进行字段填充和初始化(fillAction和initAction)
    • 会被标记为needInitBeforeUse

框架在创建组件时,会检查组件是否实现了特定接口来决定是否需要在使用前初始化:

func newCoffin(goner any) *coffin {
    _, needInitBeforeUse := goner.(Initiator)
    if !needInitBeforeUse {
        _, needInitBeforeUse = goner.(InitiatorNoError)
    }
    // ...
    return &coffin{
        goner:             goner,
        defaultTypeMap:    make(map[reflect.Type]bool),
        needInitBeforeUse: needInitBeforeUse,
    }
}

依赖收集与循环依赖检测

框架在依赖收集过程中,会为每个组件收集两种依赖:

  1. fillDependency:组件字段填充所需的依赖
  2. initDependency:组件初始化所需的依赖(通常是fillAction依赖)

关键在于,当一个字段依赖的组件被标记为needInitBeforeUse时,框架会添加一个额外的initAction依赖:

if depCo.needInitBeforeUse {
    fillDependencies = append(fillDependencies, dependency{
        coffin: depCo,
        action: initAction,
    })
}

这意味着,如果组件A依赖组件B,且B需要初始化,那么A的字段填充不仅依赖B的存在,还依赖B的初始化完成。


什么情况下会导致循环依赖的panic?

根据上述分析,当满足以下条件时,Gone框架会检测到循环依赖并抛出panic:

  1. 两个或多个组件之间存在相互依赖关系(A依赖B,B依赖A)
  2. 这些组件都实现了Init()方法,被标记为needInitBeforeUse

这种情况下,依赖关系会形成一个无法解决的循环:

  • A的字段填充依赖B的初始化
  • B的初始化依赖B的字段填充
  • B的字段填充依赖A的初始化
  • A的初始化依赖A的字段填充

这就形成了一个无法打破的循环依赖链,框架无法确定初始化顺序,因此会抛出panic。

三个用例的区别分析

现在我们可以解释三个用例的不同表现:

  1. 用例1:depA1和depB1都是普通Goner

    • 两个组件都没有实现Init()方法
    • 都不会被标记为needInitBeforeUse
    • 只有fillAction依赖,没有initAction依赖
    • 虽然有循环引用,但框架允许这种循环,因为它只涉及字段填充,不涉及初始化顺序
  2. 用例2:dep1和dep2都是Init Goner

    • 两个组件都实现了Init()方法
    • 都被标记为needInitBeforeUse
    • 既有fillAction依赖,也有initAction依赖
    • 依赖关系形成了真正的循环:
      • dep1.fill → dep2.init → dep2.fill → dep1.init → dep1.fill
    • 框架无法确定初始化顺序,因此报错
  3. 用例3:depA3是普通Goner,depB3是Init Goner

    • depA3没有实现Init()方法,不会被标记为needInitBeforeUse
    • depB3实现了Init()方法,被标记为needInitBeforeUse
    • 依赖关系不会形成完整的循环:
      • depA3.fill → depB3.init → depB3.fill
    • 由于depA3只有fillAction,没有initAction,所以不会形成完整的循环依赖

为什么会有循环依赖的panic?

Gone框架设计了循环依赖检测机制,主要是为了解决以下问题:

  1. 确保初始化顺序的确定性:如果存在循环依赖,框架无法确定组件的初始化顺序,可能导致某些组件在依赖未完全初始化的情况下被使用

  2. 防止初始化死锁:循环依赖可能导致初始化过程陷入死锁,特别是当所有组件都需要初始化时

  3. 提前发现设计问题:循环依赖通常表明应用程序的设计存在问题,提前检测并报错可以帮助开发者改进设计

框架通过拓扑排序算法检测依赖图中的循环,如果发现循环,就会抛出panic,提示开发者解决这个问题。

如何解决循环依赖问题?

当遇到循环依赖问题时,可以采用以下几种方法解决:

  1. 重构组件设计:

    • 重新审视组件之间的依赖关系,考虑是否可以重新设计以消除循环依赖
    • 可能需要引入新的抽象层或中间组件来打破循环
  2. 使用接口解耦:

    • 将直接依赖改为依赖接口,然后让两个组件都实现相同的接口
    • 这样可以降低组件之间的直接耦合
  3. 使用普通Goner:

    • 如果可能,将其中一个组件改为普通Goner(不实现Init()方法)
    • 如用例3所示,这样可以避免形成完整的循环依赖
  4. 使用延迟初始化:

    • 使用LazyFill()选项加载Goner, 延迟Goner的装配(fillAction)
    • 请注意:使用LazyFill()选项加载Goner的副作用:
      a. 被延迟的Goner,在名为Init、Provide、Inject这些方法中,无法使用依赖注入的字段
  5. 使用option:"lazy"延迟字段注入

    • 使用option:"lazy"选项,延迟字段注入
    • 请注意:使用option:"lazy"标记的字段,不能在名为Init、Provide、Inject的这些方法中使用;
  6. 使用事件机制:

    • 通过事件或消息机制实现组件间的间接通信
    • 这样可以避免直接的循环引用
  7. 使用第三方组件:

    • 引入一个中间组件,让原本相互依赖的两个组件都依赖这个中间组件
    • 中间组件可以持有必要的状态或提供必要的服务

示例:解决用例2的循环依赖

以下是几种解决用例2循环依赖的方法:

  1. 方法一:使用普通Goner
type dep1 struct {
    gone.Flag
    dep *dep2 `gone:"*"`
}

// 移除Init方法

type dep2 struct {
    gone.Flag
    dep *dep1 `gone:"*"`
}

func (d *dep2) Init() {}
  1. 方法二:使用接口解耦
type Dep2Interface interface {
    // 定义必要的方法
    SomeMethod() error
}

type dep1 struct {
    gone.Flag
    dep Dep2Interface `gone:"*"` // 依赖接口而非具体实现
}

func (d *dep1) Init() {}

type dep2 struct {
    gone.Flag
    // 不再直接依赖dep1
}

func (d *dep2) Init() {}
func (d *dep2) SomeMethod() error { return nil } // 实现接口
  1. 方法三:使用中间组件
type mediator struct {
    gone.Flag
    dep1 *dep1 `gone:"*"`
    dep2 *dep2 `gone:"*"`
}

func (m *mediator) Init() {
    // 在这里协调dep1和dep2的交互
}

type dep1 struct {
    gone.Flag
    // 不再直接依赖dep2
}

func (d *dep1) Init() {}

type dep2 struct {
    gone.Flag
    // 不再直接依赖dep1
}

func (d *dep2) Init() {}

更多内容:使用LazyFill()与option:lazy标签打破循环依赖

Gone框架中的延迟依赖注入:LazyFill()与option:lazy标签

Go 语言数据库事务详解:从 db.Begin 到 Tx 的正确用法 本文详解Go语言中database/sql事务的正确用法,从*sql.Tx的底层模型出发,阐述事务与连接池的关系,提供标准事务模板,并强调使用db.BeginTx控制隔离级别与超时。重点剖析常见陷阱:误用db而非tx执行SQL、defer顺序错误、忽略Commit错误、事务过长导致资源耗尽等。结合可运行示例,涵盖事务内查询、预处理语句及保存点模拟嵌套事务,全面覆盖工程实践中的关键细节。 阅读详情

相关推荐

Go GMP 调度器深度解析:从运行时原理到可复核的并发边界

Goroutine 的价值是把并发等待表达得足够廉价,使服务能把 CPU 用在真正可运行的工作上。它的边界同样明确:当到达持续超过完成时,系统必须选择在哪里排队、排多久、何时拒绝以及如何取消。高质量的并发设计不从“该开多少 goroutine”开始,而从可观测、可验证的容量合同开始:入口接受多少、队列允许等多久、下游承受多少、失败如何收敛、恢复如何验收。GMP 是实现这套合同的运行时基础,不是绕过它的理由。

一起修行,不孤单。这里有编程语言、开发工具、学习方法论和踩坑笔记。用简单的话说复杂的事,陪你从小白到进阶。周更干货,欢迎一起成长! 214

Go CPU 剖析的“地基“:信号、CAS、写屏障、无锁环形缓冲

本文通过“卡点自查表”梳理Go CPU剖析(cpuprof.go)中反直觉设计的底层逻辑,聚焦信号处理、CAS自旋锁、写屏障与无锁缓冲四大核心机制。指出所有设计皆源于信号处理器“不可阻塞、不碰堆、不持锁”的铁律,进而推导出:CompareAndSwap一次即走、环形缓冲无锁写入、预分配内存等策略的本质是向“在任意指令间被中断”这一事实妥协。结合多核并发与操作系统调度原理,揭示了高性能采样器如何在极端约束下实现低延迟、高吞吐。

不愿言弃-念何的博客 398

了解 Go 中的变量

Go语言中,变量是存储数据的容器,具有类型、名称和值三要素。通过var name type声明变量,如var a int;也可用简短声明:=自动推导类型,如appName := "SuperApp"。赋值使用=,将值复制给变量。变量名需合法,遵循驼峰命名法,不可以数字开头或使用保留字。Go设计简洁,强调可读性与开发效率,适用于现代并发与网络应用。

sinat_25548781的博客 47

Redis 从 0 到 1(二十七):JSON 体积是 Protobuf 的 3.7 倍?3 种序列化的 Go 基准测试

缓存对象直接用 json.Marshal,1 亿条 key 多花 20G 内存和 3 倍带宽。本文对 JSON / MessagePack / Protobuf 做 Go 基准测试(体积、编解码耗时、CPU),给出不同场景的选型表和统一序列化封装。

2501_92769340的博客 183

USB HID虚拟电池:Windows零驱动电源状态模拟方案

虚拟电池是一种在硬件测试与功耗分析中替代真实电池、实现可控电源状态注入的关键技术。其核心原理是通过标准USB HID协议(特别是UPS设备类)向操作系统上报可编程的AC/DC状态、剩余电量、容量参数等,绕过内核驱动限制,达成毫秒级响应与跨Windows版本兼容。该技术显著提升SoC能效验证、电池健康度校准及低电量行为触发等场景的可重复性与精度。本文基于CH554微控制器实现符合HID UPS规范的物理层虚拟电池设备,支持零驱动安装、USB原生识别与实时参数调控,适用于笔记本平台功耗建模、电源管理策略验证及自

weixin_35755188的博客 354

【C++】POCO学习总结(六):线程、线程池、同步

Poco::RunnableAdapter继承自Poco::Runnable,在Poco::RunnableAdapter构造函数中指定了类和方法;Poco::ThreadLocal是线程局部变量,也叫线程局部存储,意思是模版ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。

郭老二 5099

cpuprof.go开关、缓冲区与记账

本文详解Go语言CPU剖析的全链路机制,核心为定时信号触发栈采样、环形缓冲存储与异步写入。通过实验验证了64帧栈深度限制、1MiB缓冲区容量及样本丢失计数机制,揭示了SetCPUProfileRate控制采样频率、add函数处理信号中断、addExtra上报丢失样本等关键流程,并解析了跨平台差异与废弃特性。

不愿言弃-念何的博客 361

实战MSP-M0G3507与陶晶驰串口屏的通信协议解析

本文详细解析了MSP-M0G3507微控制器与陶晶驰串口屏的通信协议实现。内容涵盖串口配置、协议帧结构、数据校验机制及ASCII协议实战代码,重点介绍了陶晶驰串口屏的指令集应用和调试技巧,为嵌入式开发提供可靠的串口通信解决方案。

h9j8k7l6m5n的博客 867

联犀 Go SIMD 实战:视频转码从 16.5ms 到 5.46ms

联犀Go视频转码实战:在352×288测试流中单帧单核CPU耗时从16.5ms到5.46ms,区分SIMD、代码及编码策略的综合收益。保留测试条件、压测结果与适用边界。

QQ603785348的博客 334

使用亚组分析进行子组分析并可视化森林图 - R语言

通过亚组分析和森林图的结合,我们可以更好地理解不同子组之间的差异和效果大小。当然,在实际应用中,还需要考虑多种因素,如样本量、异质性等,以得到更准确的结果和结论。每个森林图中的水平线代表了每个子组的效应估计,线的长度表示了该效应估计的置信区间。假设我们有一个包含研究对象的数据框(data frame),其中包括了治疗组和对照组的结果数据,以及一些可能的影响因素作为调整变量。在本例中,我们将比较两种不同的治疗方法(A和B)对结果变量的影响,并调整了一个额外的变量。是结果变量和对照组变量的列名。

2301_79326857的博客 1235

【离线OCR】微信离线实现图片OCR文本和表格识别

基于微信本地OCR引擎(由最新版微信自动安装)。通过Python对其官方调用逻辑进行完整翻译和封装,使开发者可以用简单的API调用其强大的OCR功能。

专注于医院数据分析技术与系统开发的创作与分享。 2624

纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS

moejs 是一个纯 Go 编写的高性能 JavaScript 运行时,专为 Go 程序中的插件沙箱场景设计。发布于 2026 年 11 月,由 new-api 维护者 Calcium-Ion 开发,相较 C 版 QuickJS 快 35%,内存占用仅 81 KiB,单次调用仅 6.9 微秒。支持快速复用运行时、零拷贝解析、安全沙箱与 TypeScript 直接编译,通过 test262 80971 个用例零失败。适合高并发插件系统,如 AI 网关钩子处理,已在实际场景中实现请求吞吐量提升 8.6 倍。仓库

前端之虎陈随易 218

10、智慧变电站 - 加载vue大屏元素(整体效果)

这一篇文章非常简单,但是也非常出效果阅读前面几篇文章,都可以看到有顶部、左侧、右侧的面板,主要我不会录gif图片,大屏元素面板还有一些动态加载的效果。 vue的transition标签 Vue 提供了 transition 的封装组件,可以给任何元素和组件添加进入/离开过渡;在进入/离开的过渡中,会有 6 个 class 切换:v-enter 、v-enter-active 、v-enter-to 、v-leave 、v-leave-active 、v-leave-to。我们正好使用这个特性来达到面板进入

github_39988036的博客 1040

Go AI Agent 实战 30|Human-in-the-loop:关键操作前的人工确认

本课聚焦高风险操作的审批机制,强调仅靠Prompt无法保障安全,需在Go后端实现严格的HITL流程。通过定义waiting_approval状态、绑定具体操作与版本校验,确保审批可追溯、防并发漂移。示例展示任务状态管理、审批请求持久化及批准后重新验证逻辑,实现安全可靠的高风险操作执行。

2302_80713883的博客 252

endNote X9 增加 / 删除参考文献 文献编号自动更新

EndNote X9 插入参考文献常见问题总结。增删参考文献 文献编号自动更新

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 7496

YOLO26科研优化:多损失函数(EIoU、SIoU等)融合,让边界框回归精度再上台阶

将原有损失函数替换为我们编写的MultiLoss。例如,在bbox_loss。

LXY_LOVE36的博客 172

运行go web服务,检测mysql服务和端口

如果你的窗口里显示的是别的报错文字(比如 ‘xxx’ 不是内部或外部命令、系统找不到指定的路径、或 Go 编译报错),把那几行原文发我,我再精确修——不过现在这版 bat 已经把最常见的三个坑(数据库、端口、闪退看不到错误)都堵上了。启动 MySQL:用干净的 my.ini 直接起 mysqld.exe(绕开 phpstudy 面板配置),验证连通:oa_admin_rule 554 行、oa_admin 2 行,数据完好。服务本身还能起来,但登录、菜单全依赖数据库,所以你看到的是红色警告 + 登录失效。

xinhuanjieyi的博客 168

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

cpuprof.go栈回溯、定时器与平台差异

sigprof() 信号处理器从寄存器状态出发,通过多路径回溯栈帧(含 CGO、vDSO、系统调用等),最多采集64帧,失败时归入 _System 等伪函数。采样结果双写至 pprof 和 trace,实现零成本共享。setcpuprofilerate() 通过关闭旧定时器、设置新频率并触发信号,确保采样精准可控,避免死锁与抢占干扰。

不愿言弃-念何的博客 53

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

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

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

2026-11-05-Go内存管理面试

内存分配器分层、三色标记、写屏障、STW、内存泄漏——Go 内存管理这块面试最容易问懵。这篇把分配器到 GC 到泄漏排查串成十连问,每题配答案框架和追问应对,文末给 GC 调优对照表。

利威尔的博客,主要分享一些go后端,agent相关知识,都是最新最前沿而且是免费的,在我的专栏里有各种方向的详细分类和内容整理,详细内容请阅读主页置顶文章,希望对你有帮助。 369

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

2026-11-04-Go批量导出实战

一个后台导出接口,订单量冲到 2 万后内存飙到 90%、P99 到 12 秒。复盘发现三个批量任务的经典坑:全量加载、全量拼字符串、串行写。这篇用分页游标+errgroup并发+信号量限流+写临时文件四招改完,P99 压到 900 毫秒,文末给批量任务自查清单表。

利威尔的博客,主要分享一些go后端,agent相关知识,都是最新最前沿而且是免费的,在我的专栏里有各种方向的详细分类和内容整理,详细内容请阅读主页置顶文章,希望对你有帮助。 380

go消息推送之极光推送 (JPush REST API + SDK,覆盖安卓与iOS)

使用 gorush有个绕不开的问题:国内安卓设备上 FCM 基本不可达,华为、小米、OPPO、vivo 各自为政——此时可用极光推送(JPush)作解决方案。它的思路和前面几家都不一样:App 集成极光 SDK 后拿到统一的 RegistrationID,服务端发一条 REST 请求,极光云端自动把消息路由到 APNs、各家厂商通道或极光自有长连接。这里给出了:一个用纯标准库直接调用极光的;另一个用社区维护的,类型化参数,接口注释与官方文档逐条对应。两个功能相同,可放在一起对比学习。

qq_40467670的博客 175

Go语言第十八章(架构设计)

本文讲解 Go Modules 与项目结构,是 Go 多包项目、依赖管理的基础教程。从`go mod init`初始化模块、`go mod tidy`自动整理依赖入手,介绍模块路径、go.mod 与 go.sum 的作用;讲解自定义包导入规则、首字母大小写控制导出权限。同时介绍社区常用目录规范:cmd 存放程序入口、internal 为模块私有代码、pkg 用于对外可引用库。演示国内 GOPROXY 镜像配置,以 color 库为例说明第三方依赖引入流程。核心要点:一个 go.mod 对应一个模块,一个目录

qq1195566313的博客 226

2026-11-08-Go-defer-panic-recover面试

defer 的参数什么时候求值、多个 defer 什么顺序、recover 为什么有时救不回来、nil 指针包进接口为什么不等于 nil——Go 错误处理三件套的坑最多。这篇串成十连问,每题配答案框架和追问应对,文末给坑位表。

利威尔的博客,主要分享一些go后端,agent相关知识,都是最新最前沿而且是免费的,在我的专栏里有各种方向的详细分类和内容整理,详细内容请阅读主页置顶文章,希望对你有帮助。 540

go 中 GORM 结构体 Tag 配置:列名映射、可空字段与读写权限

这里给出一个样例,以下结构体将消息通知映射到数据库表,字段通过gorm:"..."下文说明column列名映射、指针类型的可空语义,以及->读写权限。

qq_40467670的博客 98

ubuntu24.04安装BaiduPCS-Go(百度网盘命令行客户端)

或者直接将这个文件下载下来之后上传到服务器上的/opt/baiduupcs下。# 下载最新版本(可去Github仓库【】找最新release替换版本号 )如果看到下面的版本输出则安装成功。# 移动到系统PATH目录。

qq_34944795的博客 97

从“通讯录”到“组织引擎”:《分析模式》当责模型演进与Go实战

本文基于《分析模式》的组织建模思想,通过Go语言实现从“重复通讯录”到“灵活组织引擎”的演进:先用Party泛化人与组织,再以自关联+防环约束实现动态层级,最终将关系实体化为OrgStructure,支持多维度、可插拔规则。模型逐步实现高内聚、低耦合、可扩展,让业务规则在代码中“呼吸”,打造坚如磐石又灵活如水的领域层。

技术专栏 182
上一篇: Gone v2.0.3发布,新增allowNil 选项:优雅处理可选依赖
下一篇: Go语言进化之旅:从1.18到1.24的语法变革
dapeng-大鹏
博客等级 码龄16年 1349粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dapeng-大鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值