Go 包的组织和命名

danceyoung · · 3200 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

原文:https://github.com/danceyoung/paper-code/blob/master/package-style-guideline/packagestyleguideline.md # Go 包的组织和命名 原文:https://rakyll.org/style-packages/ Go和其他语言一样,也涉及到命名和代码的组织。组织良好的代码具有很强的交流性、可读性和易用性,和设计良好的API一样重要。当其他用户阅读你代码的时候,包的位置、命名和结构分层的设计是他首先接触的东西。 本文通过比较通用且很好的实践例子来为你介绍Go包的规范,并不是一定要遵守的规则。实际中你要根据自己的需要来挑选最适合你项目的解决方案。 ## 包 所有的go代码都被组织在包中。一个包其实就是包含很多`.go`文件的一个路径,这样就实现了代码的组织和互相隔离,阅读代码从一个包开始。要想写好go代码,要不断理解包和基于包多实践。 ## 包的组织 我们从这2方面的建议开始:怎么组织go代码和包位置设计的约定。 ### 使用多个文件 一个包是包含了很多`.go`文件的路径。你要根据功能逻辑,充分地把代码分在不同的文件中,这样才有更好的可读性。 比如,`http`包就是根据http的不同功能分成不同的对应文件,就像下面所示的四个文件一样。 ``` - doc.go // package documentation - headers.go // HTTP headers types and code - cookies.go // HTTP cookies types and code - http.go // HTTP client implementation, request and response types, etc. ``` ### 类“以类聚“ 一个小的规范,尽量把类型声明在被使用的文件中,这样就会让其他人根据功能更容易的找到对应的类型,而不是放在一个叫`model`的包中。 比如`header`的结构体应该声明在`header.go`文件中。 ``` package http // Header represents an HTTP header. type Header struct {...} ``` 另外注意到`Header`的结构体在`header.go`文件的最上面,golang本身并没有强性要求这样做,但把基础的核心的类型放在对应文件的最上面,是一个很好的做法。 ### 按照功能职责设计 在golang中是按照功能职责设计的,即每个包都要有一定的真实业务含义。 但在其他语言中会把类型统一放在`model`包中,甚至只有类型的定义,这样我们很难找到某个类型是在哪里、哪些文件中被使用,且一旦修改了某个类型,我们不知道影响的范围。 所以在golang中我们不会如下这样设计的 ``` package models // DON'T DO IT!!! // User represents a user in the system. type User struct {...} ``` 在该示例中,我们应该把`User`声明在他被使用的包中,像下面这样 ``` package mngtservice // User represents a user in the system. type User struct {...} func UsersByQuery(ctx context.Context, q *Query) ([]*User, *Iterator, error) func UserIDByEmail(ctx context.Context, email string) (int64, error) ``` ### 提供例子来解释不清晰的引用包 有些情况下,你并不能在一个独立的包中提供所有要使用的类型。比如你想在一个包中实现一个接口,但是这个接口所在的包和你这个包不是同一个包,或者有些类型是在第三方包中,这样就会很不清晰。此时就需要提供例子来说明这些包是怎么一起用的。 如果你的代码中引用来一些不标准的包,通常需要提供一些代码例子来说明一下。例子会提高那些不太容易被发现包的透明度。 ### 不要在main包中导出任何标识符 一个标识符可以被导出(首字母大写),以允许其他包应用他。 但是`main`包不允许其他包导入,所以在`main`包导出标识符,没有任何意义。也有些例外,就是`main`包将要被构建入a .so, or a .a or Go plugin. ## 包的命名 包的名称和导入路径是你包的重要标识,并且它代表了你的包包含的所有东西。所以包的命名一定要“见文识意“,因为这样不仅提高了代码的质量,也为你的用户提高了代码的可读性。 ### 名称要小写 包的名称应该要小写,不要用下划线your_package或驼峰yourPackage的命名样式。更详细的介绍可以参考[官方博客](https://blog.golang.org/package-names),专门介绍包的命名规则。 ### 精、简、短、见文识意 包名应该精简短,且名称有唯一性并能见文识意。就是你的用户能从包名里看出包的代码逻辑和使用意图。 避免一个泛泛的名称,比如`common`,`utils`. ``` import "pkgs.org/common" // DON'T!!! ``` 避免命名重复,避免用户引用里同一个名称的包,但却是2个不同的包,这样容易产生混淆。 如果你起不好一个名称,你需要重新梳理你的业务需求、整个架构或代码的组织。 ### 导入路径 避免将您的自定义存储库的结构暴露给用户。也要符合`GOPATH`约定。 避免在导入路径中包含`src/`,`pkg/`部分。 ### 避免复数名称 在golang中,尽量避免以复数的形式命名,虽然go内置的包也有复数形式(`strings`, `errors`)。这样的规范会让其他开发语言的程序员感到很奇怪,但这就是go的设计哲学。比如不能命名为`httputils`,而要命名为`httputil` ``` package httputils // DON'T DO IT, USE SINGULAR FORM!! ``` ### 重命名引用包 如果你引用了好几个包,但是刚好包名却一样,这时为了让代码有更好的阅读性,你需要对某些包进行重命名,避免混淆。命名的规范可以参考本文介绍的规范,至于你要重命名哪些包,根据你自己的情况。但建议,比如你要重命名go标准包,加一个前缀表示这是来自go的标准包,`gourl`,`goioutil`. ``` import ( gourl "net/url" "myother.com/url" ) ```

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3200 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传