奇技 · 指南

Golang作为当下云开发中最为流行的语言之一,越来越受到广大程序员的青睐。开发Golang项目经常遇到的一个常见问题是如何组织项目结构布局。今天作者从项目结构以及对内部、外部包的引用来讲讲布局问题,希望对大家有所帮助。

开始编码之前,我们需要先明确一些问题:

  • 项目结构如何反映代码的引入方式?

  • 除代码外,如何组织项目的命令行工具?

  • 如何灵活的在不同模块间组织项目代码?

  • 多个包如何在一个模块中共存?

我们先明确一些名词和概念:

Internal packages,内部私有包,只能从其模块中的其他包引入,不能被外部包引入。用户可以使用 go get 安装需要的外部包。

1

Helloworld

我们打开一个项目,项目路径是模块名。项目的 go.mod 文件包含以下行:

module github.com/qidian/modlib

Go项目通常通过其GitHub路径命名。Go还支持自定义名称,本文暂不赘述,之后开新帖再说。我们可以暂时用`github.com/your-handle/your-project`或`your-project-domain.io`替换`github.com/qidian/modlib`。

模块名称非常重要,因为他是项目代码中引入包名的基础:

2

项目布局

先来看一个项目 modlib 的目录和文件布局:

├── LICENSE├── README.md├── config.go├── go.mod├── go.sum├── clientlib│   ├── lib.go│   └── lib_test.go├── cmd│   ├── modlib-client│   │   └── main.go│   └── modlib-server│       └── main.go├── internal│   └── auth│       ├── auth.go│       └── auth_test.go└── serverlib    └── lib.go

让我们从根目录中的文件开始。

go.mod 是模块定义文件。它包含上面显示的模块名称,我的项目没有依赖项。依赖项与项目布局设计无关。有需要的同学可以从 Golang 官方博客学习。go.sum 由 go tools 管理,其包含所有依赖项校验值。

config.go,这是我们查看的第一个代码文件,它包含一个简单的 Config()函数:

package modlibfunc Config() string {return "modlib config"}

第一行申明包名,由于该文件位于模块的顶层,因此其程序包名称即为模块名称。

关于如何引入 github.com/qidian/modlib ,我们来看一个例子:

package mainimport "fmt"import "github.com/qidian/modlib"func main() {  fmt.Println(modlib.Config())}

因此,如果您的模块提供单个 package,或者您要从模块的顶层软件包中导出代码,则将其所有代码放在模块的顶层目录中,并命名该 package 作为模块路径的最后一部分(除非您使用更灵活的 vanity imports)。

3

引用外部包

clientlib / lib.go 是我们对 clientlib 模块封装的文件。文件名可以根据业务逻辑来命名:

package clientlibfunc Hello() string {return "clientlib hello"}

我们再来看下面这个例子,通过 github.com/qidian/modlib/clientlib 导入 clientlib:

package mainimport "fmt"import "github.com/qidian/modlib"import "github.com/qidian/modlib/clientlib"func main() {  fmt.Println(modlib.Config())  fmt.Println(clientlib.Hello())}

serverlib目录包含了另一个用户可以引入的package。这里展示了多个程序包如何在代码结构中并存。

关于包嵌套,它可以根据需要增加目录层级。我们可见的  package 名称由模块根目录的相对路径确定。例如,如果我们有一个 `clientlib/tokens` 的子目录 ,并在tokens包中包含一些代码,则用户将使用如下代码引入该目录。

import "github.com/qidian/modlib/clientlib/tokens“

对于一些模块而言,一个顶级 package 就足够业务开发了。在本例中没有用户可导入的 package 子目录,但是所有代码都在 modlib 的单个或多个 Go 文件中。

4

Commands

一些Go项目还需要制作可执行程序,我们一般会再增加一个cmd目录。

该目录是项目所有命令行程序的常规位置。程序的命名方案通常为:

用户可以使用go工具按如下方式安装此类命令:

$ go get github.com/qidian/modlib/cmd/cmd-name# Go downloads, builds and installs cmd-name into the default location.# The bin/ directory in the default location is often in $PATH, so we can# just invoke cmd-name now$ cmd-name ...

在modlib中,提供了两个不同的命令行程序作为示例:modlib-client和modlib-server。在每个代码中,代码都在包main中;文件名为main.go。

这是我们在测试环境上运行的命令:

$ go get github.com/qidian/modlib/cmd/modlib-client$ modlib-clientRunning clientConfig: modlib configclientlib hello$ go get github.com/qidian/modlib/cmd/modlib-server$ modlib-serverRunning serverConfig: modlib configAuth: thou art authorizedserverlib hello# Clean up...$ rm -f `which modlib-server` `which modlib-client`

我们来看看 modlib-serve.go 是如何从 modlib 中导入其他代码的:

package mainimport (  "fmt""github.com/qidian/modlib""github.com/qidian/modlib/internal/auth""github.com/qidian/modlib/serverlib")func main() {  fmt.Println("Running server")  fmt.Println("Config:", modlib.Config())  fmt.Println("Auth:", auth.GetAuth())  fmt.Println(serverlib.Hello())}

Golang 里的绝对导入适用于引入package和二进制命令,这是 clientlib 中的代码需要引入 modlib 时的例子:

github.com/eliben/modlib

4

私有包

另一个重要概念是私有包,也就是项目内部使用的软件包,并且我们不想导出给外部用户。由于语义版本控制,这在Go模块中尤其重要。您的项目在v1中导出的所有内容都将成为公共API,并且必须遵守语义版本兼容性。

Go工具将内部包识别为特殊路径,只有同一模块中的软件包可以引入它。如果我们尝试在外部模块代码中引用,则会抛错:

use of internal package github.com/eliben/modlib/internal/auth not allowed

在本文样例中,internal中只有一个package。而在实际的工程项目里通常会有一堆完整的package目录树。

将内部API重构并将其导出给其他同学很容易,但是使用外部API并取消导出会很麻烦。所以我在开发时会尽可能地将模块需要的私有包和代码放入内部包中。最后再举个例子,如果一个网站项目 repo 中,我们将代码安排在 internal/website中。用于项目的内部工具和脚本也是如此。这样一来项目的根目录是最清晰并且对开发者来说更友好。理想情况下,开发者通过项目代码布局就可以大致了解他们想了解的东西所在位置,因此将一些代码放在内部会很有意义。

相关文章

  • https://blog.golang.org/v2-go-modules

  • https://blog.golang.org/module-compatibility

往期精彩回顾

TensorNet——基于TensorFlow的大规模稀疏特征模型分布式训练框架

一种通过云配置处理应用权限弹框的方案

360Stack裸金属服务器部署实践

360技术公众号

技术干货|一手资讯|精彩活动

扫码关注我们

go 项目 cmd目录_Golang 项目布局浅析相关推荐

  1. Vue 学习笔记(4)Vue-cli4 项目搭建 + 目录结构 + 项目打包、部署

    VueCLI 脚手架 Vue CLI 介绍 Vue CLI 安装 Node.js 环境准备 安装 Vue 脚手架 第一个 Vue 脚手架项目 命令创建项目 图形化界面创建项目 vue-cli4 目录结 ...

  2. Go项目的目录结构基本布局

    前言 随着项目的代码量在不断地增长,不同的开发人员按自己意愿随意布局和创建目录结构,项目维护性就很差,代码也非常凌乱.良好的目录与文件结构十分重要,尤其是团队合作的时候,良好的目录与文件结构可以减少很 ...

  3. 批量清理Unity项目Library目录 降低项目空闲占用空间

    Unity项目批量清理工具 Python程序运行截图 结尾云盘下载连接和源码 百度云盘连接 蓝奏云 源码 Python程序运行截图 结尾云盘下载连接和源码 CSDN下载连接 底下有其它云盘下载连接 h ...

  4. 完整的项目工程目录结构

    为什么80%的码农都做不了架构师?>>>    在项目开发过程中,如何有序的保存项目中的各类数据文件,建立一个分类清晰.方便管理的目录结构是非常重要的. 综合以前的项目和一些朋友的项 ...

  5. 2022年Java项目课程目录

    一.2022Java项目课程目录 Java项目课程01:课程概述 Java项目课程02:系统概述 Java项目课程03:涉及知识点 Java项目课程04:需求分析 Java项目课程05:系统设计 Ja ...

  6. 分享完整的项目工程目录结构

    在项目开发过程中,如何有序的保存项目中的各类数据文件,建立一个分类清晰.方便管理的目录结构是非常重要的. 综合以前的项目和一些朋友的项目结构,我整理了一份我觉得还不错的项目目录结构. 在这里分享给大家 ...

  7. Golang 项目布局浅析

    女主宣言 Golang作为当下云开发中最为流行的语言之一,越来越受到广大程序员的青睐.开发Golang项目经常遇到的一个常见问题是如何组织项目结构布局.今天作者从项目结构以及对内部.外部包的引用来讲讲 ...

  8. vuecli项目文件命名_vue.js学习笔记(一)——vue-cli项目的目录结构

    vue.js是一套构建用户界面的渐进式框架.vue采用自底向上增量开发的设计.vue的核心库只关心视图层,非常容易学习,非常容易与其它库和已有项目整合.vue完全有能力驱动采用单文件组件和vue生态系 ...

  9. Android项目的目录结构

    引言 本篇将通过HelloWorld项目来介绍Android项目的目录结构.本文的主要主题如下: 1.HelloWorld项目的目录结构 1.1.src文件夹 1.2.gen文件夹 1.3.Andro ...

最新文章

  1. 【GStreamer】官网基本教程学习(basic-tutorial)
  2. ALICE源代码分析
  3. HDU-2476 String painter 区间DP
  4. 2019年四月计算机语言排名,2019编程语言排行榜_编程语言排行榜2019年4月 TIOBE编程语言排行榜2019年最...
  5. 从 vue3 和 vite 源码中,我学到了一行代码统一规范团队包管理器的神器
  6. vivado安装_Vivado下载与安装指南
  7. 快速入门系列之 Rust 语言 GitChat连接
  8. Spring Cloud构建微服务架构(七)消息总线
  9. 大型K8s沙龙来啦,火速报名——Kubernetes Cloud Native Meetup
  10. 大数据Hadoop生态圈
  11. 基于SSM框架的生源地助学贷款管理系统的设计与实现
  12. 笔记本此计算机到网络出现一个叉,笔记本电脑无线网络不可用并显示红叉的解决方...
  13. linux下chm阅读器kchmviewer中文乱码解决方法
  14. python计算天数包含几周_如何在python中计算几周内两个日期之间的差异
  15. [unity2D] 迷你拼图
  16. 程序员月薪过3万,却感叹活得不如狗,北漂压力太大又不敢辞职
  17. 关于主机的思维导图_关于开展思维导图培训的通知
  18. 神经网络(Neural Networks)简介
  19. 帝国根目录查阅 帝国CMS根目录一览表 ECMC根目录都是什么意思?
  20. 小苹果歌词――筷子兄弟

热门文章

  1. python3 isinstance用法_对python中assert、isinstance的用法详解
  2. 搜狗高速浏览器提示您 怎么关闭_那些浏览器中的快捷键们
  3. 能熟练掌握和应用计算机基础知识,浙江省大学生计算机基础知识与应用能力等级考试二级(V......
  4. php e all e notic,error_reporting(E_ALL ^ E_NOTICE)详细说明 | 慢生活的记忆
  5. 获取rabbitmq连接对象_RabbitMQ——简单队列
  6. matlab 地埋管温度场,地埋管换热器周围土壤冻结温度场的模拟研究
  7. java怎么获取文本里的值_怎么获取到text中的文本,或者title中的值
  8. Leetcode-199二叉树的右视图(二叉树左视图)
  9. 在AWS S3的连接过程中发生java.lang.BootstrapMethodError: call site initialization exception
  10. java语言实现图的深度优先遍历