Golang中共享结构体的最佳存放位置探讨
Golang中共享结构体的最佳存放位置探讨 我正在构建一个客户端/服务器应用程序,其中客户端和服务器共享相同的结构体。我将它作为GitHub上的两个独立项目进行开发,但不确定应该把共享代码放在哪里。据我分析,我有以下几种选择:
- 放在服务器端,然后导入到客户端
- 放在客户端,然后导入到服务器端
- 在两个项目中重复相同的代码
- 将代码放在独立项目中,从两端分别导入
第一种方案似乎是最佳选择,但我想确认其他人是否认同,或者是否有其他更好的实现方式。
这看起来庞大且复杂,但我会研究一下,谢谢。
仅为几个结构体这样做值得吗?不过我认为这种方式是最灵活的。
使用最后一个。
我的所有代码现在都整合到了一个代码库中,感谢大家的帮助。
将所有内容放在一个代码仓库中。 但是将共享代码放在单独的包中(在此仓库内),客户端和服务器都可以导入该包。
那么在主函数中用一个switch语句来触发其中一个或另一个?我可以这样实现。
我曾经是开发人员,但现在只编写小型应用程序,因此对最佳实践有些生疏。不过我正在慢慢重新学习。感谢您的帮助。
这样做是值得的。你的结构体(也可以只是一个变量)是一个依赖项。任何依赖项都必须单独打包。这是一个良好的实践,既符合逻辑又符合惯用法。
// 代码示例保留原样
func main() {
fmt.Println("hello world")
}
我认为在我的情况下有点小题大做,我只需要处理2-3条消息,所以请求和响应最多也就6个结构体。我只是想确认自己理解正确,以备将来需要大规模处理时能得心应手。
我也会记住gRPC,说不定将来会派上用场。
@digininja 这确实是一种方法。我相信还需要做些额外研究,但 cobra 是个非常棒的库,可以帮助你实现这个功能/以支持这种方式的结构来组织代码:
@digininja 我认为如果你能分享一些背景信息会很有帮助:为什么它们是两个独立的项目?
将它们放在同一个代码库中是非常常见的做法,因为这样可以减轻两者之间兼容性方面的一些困扰。当你对代码进行修改时,客户端和服务器可以同时使用相同版本的代码并利用这些更改。我个人建议避免将其拆分为两个代码库。
1 个赞
@digininja 我看到有些人会构建一个二进制文件,然后使用子命令来选择要执行的操作:
./project server
# 或者运行客户端
./project client
这样你就可以发布一个同时充当服务器和客户端的构建产物,而且体积可能不会有太大差别。由于你不需要两个Go二进制文件,最终体积可能会小得多。
它们分属两个仓库,因为我认为应该这样做。我刚刚尝试了一下,才意识到我可以这样组织:
github.com/digininja/project/server
github.com/digininja/project/client
让它们分别构建不同的二进制文件。
这意味着我还可以这样设置:
github.com/digininja/project/shared
将所有共享内容放在同一个仓库中托管。
我仍在努力理解这一切的工作原理和应有的结构。
在我看来现在正是研究gRPC的好时机。我目前也拥有多个代码库,包括独立的客户端和多个服务器(服务)。所有通信都通过gRPC完成,因此我的所有消息(结构体)都在单个protobufs代码库中定义,这些github.com/user/stubs/*在所有客户端和服务之间共享。不确定在您的情况下这是好是坏,但我认为至少值得了解一下。
好的,我会按照要求处理。
好的,我会那样做。
关于项目结构,我目前有:
github.com/digininja/server
github.com/digininja/client
我可以把这些共享文件放在:
github.com/digininja/server/shared
还是我最好把它们放在一个新的代码仓库里?
github.com/digininja/shared
我仍在努力理解如何正确地规划布局。
"单一代码库"的理念相当流行,我在Go项目中使用这种方式也取得了良好效果。以下是讨论该概念的其他文章:
DigitalOcean技术博客 – 2017年10月11日

克苏鲁:在可扩展代码库中组织Go代码
在DigitalOcean,我们使用名为"克苏鲁"的单一代码库来组织Go代码已近三年。单一代码库是指包含许多不同项目和库的整体式代码仓库。Bryan Liles最早在…

驯服Go依赖管理
在DigitalOcean内部,我们的Go代码库曾存在一个逐渐发酵的问题。独立项目在独立的Git仓库中开发,为了最小化依赖升级带来的影响…

DigitalOcean的Go语言实践
我们在DigitalOcean如何使用Go语言
在Go语言项目中,共享结构体的最佳实践是将其放在独立的模块中,然后从客户端和服务器端分别导入。这种方式避免了代码重复,提高了可维护性,并遵循了Go模块化设计原则。以下是详细解释和示例代码。
为什么选择独立项目?
- 单一职责:共享代码独立于客户端或服务器逻辑,便于管理。
- 版本控制:可以独立版本化共享模块,客户端和服务器端通过版本号引用,避免破坏性变更。
- 依赖清晰:客户端和服务器端显式依赖共享模块,减少耦合。
实现步骤
- 创建独立GitHub仓库:例如
github.com/yourusername/shared-models。 - 定义共享结构体:在独立项目中创建Go模块。
- 客户端和服务器端导入:通过Go模块系统引用共享模块。
示例代码
假设共享结构体用于用户数据。
在独立项目 shared-models 中:
- 文件结构:
shared-models/ ├── go.mod └── models/ └── user.go go.mod内容:module github.com/yourusername/shared-models go 1.21models/user.go内容:package models type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` }
在服务器端项目中:
- 导入共享模块:
import "github.com/yourusername/shared-models/models" func handleUserRequest() { user := models.User{ ID: 1, Name: "Alice", Email: "alice@example.com", } // 处理用户逻辑... } - 在
go.mod中添加依赖:require github.com/yourusername/shared-models v0.1.0
在客户端项目中:
- 同样导入共享模块:
import "github.com/yourusername/shared-models/models" func displayUser() { user := models.User{ ID: 1, Name: "Alice", Email: "alice@example.com", } // 使用用户数据... } - 在
go.mod中添加相同依赖。
其他方案的问题
- 放在服务器端或客户端:会导致一端主导共享代码,可能引入不相关依赖,违反关注点分离。
- 重复代码:违反DRY原则,维护困难,容易产生不一致。
通过独立模块,您可以确保结构体定义一致,且易于测试和扩展。使用Go模块的版本管理(如 go get github.com/yourusername/shared-models@v1.0.0)可以进一步控制依赖。

