Golang中共享结构体的最佳存放位置探讨

Golang中共享结构体的最佳存放位置探讨 我正在构建一个客户端/服务器应用程序,其中客户端和服务器共享相同的结构体。我将它作为GitHub上的两个独立项目进行开发,但不确定应该把共享代码放在哪里。据我分析,我有以下几种选择:

  • 放在服务器端,然后导入到客户端
  • 放在客户端,然后导入到服务器端
  • 在两个项目中重复相同的代码
  • 将代码放在独立项目中,从两端分别导入

第一种方案似乎是最佳选择,但我想确认其他人是否认同,或者是否有其他更好的实现方式。

17 回复

太棒了!很高兴我们能帮上忙!

更多关于Golang中共享结构体的最佳存放位置探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这看起来庞大且复杂,但我会研究一下,谢谢。

仅为几个结构体这样做值得吗?不过我认为这种方式是最灵活的。

使用最后一个。

我的所有代码现在都整合到了一个代码库中,感谢大家的帮助。

将所有内容放在一个代码仓库中。 但是将共享代码放在单独的包中(在此仓库内),客户端和服务器都可以导入该包。

那么在主函数中用一个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/*在所有客户端和服务之间共享。不确定在您的情况下这是好是坏,但我认为至少值得了解一下。

https://grpc.io/

好的,我会按照要求处理。

好的,我会那样做。

关于项目结构,我目前有:

github.com/digininja/server github.com/digininja/client

我可以把这些共享文件放在:

github.com/digininja/server/shared

还是我最好把它们放在一个新的代码仓库里?

github.com/digininja/shared

我仍在努力理解如何正确地规划布局。

"单一代码库"的理念相当流行,我在Go项目中使用这种方式也取得了良好效果。以下是讨论该概念的其他文章:

DigitalOcean博客图标 DigitalOcean技术博客 – 2017年10月11日

文章配图

克苏鲁:在可扩展代码库中组织Go代码

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


DigitalOcean博客图标 DigitalOcean技术博客 – 2015年2月20日

文章配图

驯服Go依赖管理

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


Speaker Deck图标 Speaker Deck

演示文稿封面

DigitalOcean的Go语言实践

我们在DigitalOcean如何使用Go语言


http://danluu.com/monorepo/

在Go语言项目中,共享结构体的最佳实践是将其放在独立的模块中,然后从客户端和服务器端分别导入。这种方式避免了代码重复,提高了可维护性,并遵循了Go模块化设计原则。以下是详细解释和示例代码。

为什么选择独立项目?

  • 单一职责:共享代码独立于客户端或服务器逻辑,便于管理。
  • 版本控制:可以独立版本化共享模块,客户端和服务器端通过版本号引用,避免破坏性变更。
  • 依赖清晰:客户端和服务器端显式依赖共享模块,减少耦合。

实现步骤

  1. 创建独立GitHub仓库:例如 github.com/yourusername/shared-models
  2. 定义共享结构体:在独立项目中创建Go模块。
  3. 客户端和服务器端导入:通过Go模块系统引用共享模块。

示例代码

假设共享结构体用于用户数据。

在独立项目 shared-models 中:

  • 文件结构:
    shared-models/
    ├── go.mod
    └── models/
        └── user.go
    
  • go.mod 内容:
    module github.com/yourusername/shared-models
    
    go 1.21
    
  • models/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)可以进一步控制依赖。

回到顶部