Go Package 编码规范总结

Go

在 Go 语言中一样会涉及命名和组织内容. 井井有条的 Go 代码更易于发现, 使用和阅读. 组织良好的代码与设计良好的 API 一样重要. 包的位置, 名称和结构是用户与之接触的第一印象.

本文档的目的是指导您使用常见的良好做法来制定规范. 您需要根据自己的判断为特定的场景选择最合适的解决方案.

所有的 Go 代码都组织在软件包中. Go 中的软件包只是一个目录/文件夹, 其中包含一个或多个 .go 文件. Go 软件包提供了隔离和组织代码的功能, 类似目录/文件夹在计算机上组织文件的方法.

所有 Go 代码都位于一个包中, 而包是访问 Go 代码的入口点. 了解和建立关于软件包的良好实践对于编写有效的 Go 代码很重要.


包组织

让我们从如何组织 Go 代码并解释有关查找 Go 软件包的约定的建议开始.

使用多个文件

软件包是包含一个或多个 Go 文件的目录. 可随意将代码分成逻辑多份的文件, 来实现最佳可读性.

例如, 一个 HTTP 包可能以根据文件处理的 HTTP 方面分为不同的文件. 在以下示例中, HTTP 包分为几个文件: header 类型及代码, cookie 类型及代码, 实际的 HTTP 实现, 以及该包的文档.

- doc.go       // 包稳定
- headers.go   // HTTP headers 类型及代码
- cookies.go   // HTTP cookies 类型及代码
- http.go      // HTTP client 实现, 请求及响应类型等.

保持类型紧密

根据经验, 使类型更靠近使用它们的位置. 这样任何维护人员 (不仅是原始作者) 都可以轻松找到该类型. headers.go 就是一个放置 Haeader 结构体类型的好地方.

$ cat headers.go
package http

// Header 代表一个 HTTP header.
type Header struct {...}

虽然, Go 语言并没有限制您定义类型的位置, 但通常最好的做法是将核心类型放置在文件顶部.

按责任组织

其他语言的一个常见做法是将类型组织在一起叫做模型或类似. 在 Go 中, 我们根据代码的功能职责来组织.

package models // 不要这样写!!!

// User 代表系统中的一个用户
type User struct {...}

User 类型应该存在于服务层程序包中, 而不是创建一个 models 程序包并在其中声明所有实体类型.

package mngtservice

// User 代表系统中的一个用户
type User struct {...}

func UsersByQuery(ctx context.Context, q *Query) ([]*User, *Iterator, error)

func UserIDByEmail(ctx context.Context, email string) (int64, error)

针对 godoc 优化

在包 API 设计的早期阶段使用 godoc 来查看你程序包的 API 如何在稳定上呈现是一个很好的练习. 有时, 可视化也会对设计产生影响. Godoc 是用户使用程序包的方式, 因此可以对其进行调整以便更易于访问. 运行 godoc -http=<hostpost> 来启用一个本地的 godoc 服务器.

提供示例来填补空白

在某些情况下, 你可能无法从单个软件包中提供所有相关类型. 这样做可能会有点麻烦, 或者你可能想从单独的程序中发布公共接口的具体实现, 或者这些类似可能归第三方程序所有. 提供示例以帮助用户发现和理解如何将它们一起工作.

$ godoc cloud.google.com/go/datastore
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error)
...

NewClient 与 option.ClientOptions 一起工作, 但它既不是数据存储包也不是导出所有选项类型的选项包.

$ godoc google.golang.org/extraoption
func WithCustomValue(v string) option.ClientOption
...

如果你的 API 需要导入许多非标准程序包, 通过添加 Go example 来为您用户提供一些有效代码是很有用的.

示例是提高难找的程序包可见性的好办法. 例如, datastore.NewClient 的示例可能引用了 extraoption 包.

不要从 main 导出

标识符 exported 可以允许其他包访问.

主程序包是不可导入的, 所以不需要从主程序包导出标识符. 如果要将包构建为二进制文件, 请不要从主程序包中导出标识符.

该规则的例外情况可能是 .so, a .a 后 Go 插件内置的主程序包. 在这种情况下, 可能会通过
cgo 的导出功能 来导出需要的标识符以供其他语言使用 Go 代码实现的功能.


包命名

包名称和导入路径都是包的重要标识符,它们代表了软件包包含的所有内容。规范的命名软件包不仅可以提高代码质量,而且可以提高用户的质量。

仅小写

软件包名称应为小写。请勿在软件包名称中使用snake_case或camelCase。 Go博客有一个综合指南,其中包含有关命名包的命名示例。

简短但具有代表性的名称

软件包名称应简短,但应唯一且具有代表性。包裹的使用者应该能够仅从包裹的名称中掌握其用途。

避免使用过于宽泛的软件包名称,例如“ common”和“ util”。

import "pkgs.org/common" // 不要这么做!!!

避免用户在可能需要导入相同包的情况下出现重复名称。

如果您无法避免使用糟糕的名称,则很可能是您的整体结构和代码组织出现了问题。

清理导入路径

避免将您的自定义存储库结构暴露给用户。符合GOPATH惯例。避免在导入路径中包含src /,pkg /部分。

github.com/user/repo/src/httputil   // 不要这样做,避免SRC!

github.com/user/repo/gosrc/httputil // 不要这样做,避免使用GOSRC!

没有复数

在go中,程序包名称不能为复数。对于那些来自其他语言并保留了名称多元化的习惯的程序员来说,这是令人惊讶的。不要将包命名为httputils,而是httputil!

package httputils  //不要这样做,请使用单数形式!

重命名应遵循相同的规则

如果要导入多个具有相同名称的软件包,则可以在本地重命名软件包名称。重命名应遵循本文提到的相同规则。没有规则应重命名哪个软件包。如果您要重命名标准软件包库,最好添加go前缀以使名称自称文档为“ Go standard library’s package”,例如gourlgoioutil

import (
    gourl "net/url"

    "myother.com/url"
)

强制使用虚拟url

go get 支持通过不同于包重定义的url的url来获取包。 这些url被称为虚拟url,要求您使用Go工具识别的特定meta标记为页面提供服务。您可以使用虚拟URL为具有自定义域和路径的包提供服务。

例如,

$ go get cloud.google.com/go/datastore

https://code.googlesource.com/gocloud检出源代码,并将其放在$ GOPATH / src / cloud.google.com / go / datastore下的工作区中。

鉴于code.googlesource.com/gocloud已经在提供此软件包,是否有可能从该URL获取该软件包?如果您强制使用虚拟URL,则答案是否定的。

为此,请在包中添加一个import语句。 go工具将拒绝从任何其他路径导入此软件包,并向用户显示友好错误。如果您不强制使用虚拟URL,则由于名称空间不同,包的两个副本将无法一起工作。

package datastore // import "cloud.google.com/go/datastore"

##包文档

始终记录包。包文档是紧挨着Package子句前面的顶级注释。对于非主包,godoc总是以“Package{pkgname}”开头,后面跟着一个描述。对于主包,文档应该解释二进制文件。

// 包ioutil实现了一些I/O实用程序函数。
package ioutil

// 命令GOP列出了系统上运行的所有进程。
package main

// 示例helloworld演示了如何使用x。
package main

使用doc.go

有时,包文档可能会非常冗长,特别是当它们提供了用法和指南的详细信息时。将包godoc移到doc.go文件。 (参考doc.go)

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://rakyll.org/style-packages/

译文地址:https://learnku.com/go/t/47034

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!