这里填写标题

  • 1. 作为 Gopher, 你知道 Go 的注释即文档应该怎么写吗?
    • 1.1. 导语
    • 1.2. 引言
    • 1.3. 什么是 GoDoc
    • 1.4. godoc 命令
    • 1.5. pkgsite 命令
    • 1.6. pkg.go.dev 内容
      • 1.6.1. 总体内容
      • 1.6.2. Documentation
    • 1.7. GoDoc 语法
      • 1.7.1. 绑定 GoDoc 与指定类型
      • 1.7.2. 换行(段落)
      • 1.7.3. 内嵌代码
    • 1.8. Overview 部分
    • 1.9. 弃用代码声明
    • 1.10. 代码示例文档
      • 1.10.1. 示例代码的声明
      • 1.10.2. 在官网上发布 GoDoc

1. 作为 Gopher, 你知道 Go 的注释即文档应该怎么写吗?

1.1. 导语

Go 一直奉行 “注释即文档” 的概念, 在代码中针对各种 public 内容进行注释之后, 这些注释也就是对应内容的文档, 这称为 GoDoc。那么作为 gopher, 你知道 GoDoc 应该怎么写吗?

1.2. 引言

刚入门 Go 开发时, 在开源项目的主页上我们经常可以看到这样的一个徽章:

点击徽章, 就可以打开 https://pkg.go.dev/ 的网页, 网页中给出了这个开源项目所对应的 Go 文档。在刚接触 Go 的时候, 我曾一度以为, pkg.go.dev 上面的文档是需要开发者上传并审核的——要不然那些文档咋都显得那么专业呢。

然而当我写自己的轮子时, 慢慢的我就发现并非如此。

划重点: 在 pkg.go.dev 上的文档, 都是 Go 自动从开源项目的工程代码中爬取、格式化后展现出来的。换句话说, 每个人都可以写自己的 GoDoc 并且展示在 pkg.go.dev 上, 只需要遵从 GoDoc 的格式标准即可, 也不需要任何审核动作。

本文章的目的是通过例子, 简要说明 GoDoc 的格式, 让读者也可以自己写一段高大上的 godoc。以下内容以我自己的 jsonvalue(https://github.com/Andrew-M-C/go.jsonvalue) 包为例子。其对应的 GoDoc 在这里 (https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue)。读者可以点开, 并与代码中的内容做参考对比。

1.3. 什么是 GoDoc

顾名思义, GoDoc 就是 Go 语言的文档。在实际应用中, godoc 可能可以指以下含义:

  • 在 2019 年 11 月之前, 表示 https://godoc.org 中的内容。
  • 现在 godoc.org 已经下线, 会重定向到 pkg.go.dev, 并且其功能也都重新迁移到这上面——下文以 “pkg.go.dev” 指代这个含义。
  • Go 开发工具的一个命令, 就叫做 godoc——下文直接以"godoc"指代这个工具。
  • pkg.go.dev 的相关命令, 被叫做 pkgsite, 代码托管在 GitHub 上——下文以 “pkgsite” 指代这个工具。
  • Go 工具包的文档以及生成该文档所相关的格式——下文以 “GoDoc” 指代这个含义。

目前的 godoc 和 pkgsite 有两个作用, 一个是用来本地调试自己的 GoDoc 显示效果; 另一个是在无法科学上网的时候, 用来本地搭建 GoDoc 服务器之用。

1.4. godoc 命令

我们从工具命令开始讲起吧。在 2019 年之前, Go 使用的是 godoc 这个工具来格式化和展示 Go 代码中自带的文档。现在这个命令已经不再包含于 Go 工具链中, 而需要额外安装:

go get -v golang.org/x/tools/cmd/godoc

godoc 命令有多种模式和参数, 这里我们列出最常用和最简便的模式:

cd XXXX; godoc -http=:6060

其中 XXXX 是包含 go.mod 的一个仓库目录。假设 XXX 是我的 jsonvalue(https://github.com/Andrew-M-C/go.jsonvalue) 库的本地目录, 根据 go.mod, 这个库的地址是 github.com/Andrew-M-C/go.jsonvalue, 那么我就可以在浏览器中打开 http://IP:{IP}:IP:{PORT}/pkg/github.com/Andrew-M-C/go.jsonvalue/, 就可以访问我的 jsonvalue 库的 GoDoc 页面了, 如下图所示:

1.5. pkgsite 命令

正如前文所说, 现在 Go 官方维护和使用的是 pkg.go.dev, 因此本文主要说明 pkgsite 的用法。

当前的 pkgsite 要求 Go 1.18 版, 因此请把 Go 版升级到 1.18。然后我们需要安装 pkgsite:

go install golang.org/x/pkgsite/cmd/pkgsite@latest

然后和 godoc 类似:

cd XXXX; pkgsite -http=:6060

一样用 jsonvalue 举例。浏览器的地址与 godoc 类似, 但是少了"pkg/", 页面如下图所示:

1.6. pkg.go.dev 内容

1.6.1. 总体内容

由于笔者在 jsonvalue 中对 GoDoc 玩得比较多, 因此还是以这个库为例子。我们打开 pkg.go.dev 中相关包的主页, 可以看到这些内容:

  • A-当前 package 的完整路径。
  • B-当前 package 的名称, 其中的 module 表示这是一个符合 go module 的包。
  • C-当前 package 的一些基础信息, 包括最新版本、发布时间、证书、依赖的包数量(包括系统包)、被引用的包数量。
  • D-如果当前 package 包含 README 文件, 则展示 README 文件的内容。
  • E-当前 package 内的 comment as document 文档内容。
  • F-当前 package 的文件列表, 可以点击快速浏览。
  • G-当前 package 的子目录列表。

如果你的 README (markdown 格式) 有子标题, 那么 pkgsite 会生成 README 下的二级目录索引。Markdown 的格式在本文就不予说明, 相信码农们都耳熟能详了。

1.6.2. Documentation

让我们点开 Documentation, 一个完整的 package, 可能包含以下这些内容:

其实 Documentation 的内容, 就是 GoDoc。Go 秉承"注释即文档"的理念, 其中 pkg.go.dev、godoc 和 pkgsite 都使用同一套 GoDoc 格式, 三者都按照该格式从文档的注释中提取, 并生成文档。

下面我们具体来说明一下 GoDoc 的语法。

1.7. GoDoc 语法

在 GoDoc 中, 当前 package 的所有可导出类型, 都会在 pkg.go.dev 页面中展示出来, 即便某个可导出类型没有任何的注释, GoDoc 也会将这个可导出内容的原型展示出来——当然了, 我们应该时时刻刻记住: 所有的可导出内容, 都应该写好注释。

GoDoc 支持//和/* … /两种模式的注释符。但是笔者还是推荐使用//, 这也是目前的注释符主流, 而且大部分 IDE 也都支持一键将多行文本直接转为注释(比如 Mac 的 VsCode, 使用 command+/)。虽然/ */在多行注释中非常方便, 但一旦看到这个, 总觉得好像是上古时代的代码 (狗头)。

1.7.1. 绑定 GoDoc 与指定类型

对于任意一个可导出内容, 紧跟着代码定义上方一行的注释, 都会被视为该内容的 GoDoc, 从而被提取出来。比如说:

// 这一行, 会被视为 SomeTypeA 的 GoDoc, // 因为它紧挨着 SomeTypeA 的定义。type SomeTypeA struct{}
// 这一行与 SomeTypeB 的定义之间隔了一行, // 所以并不会认为是 SomeTypeB 的 GoDoc。
type SomeTypeB struct{}
/*使用这种注释符的注释也是同理, 因为整个注释块紧挨着 SomeTypeC 的定义, 因此会被视为 SomeTypeC 的注释。*/
type SomeTypeC struct{}

这三个类型在 pkgsite 页面上的展示效果是这样的:

但是, 请读者注意, 按照 Go 官方的推荐, 代码注释的第一个单词, 应该是被注释的内容本身。比如前文中, SomeTypeA 的注释应该是// SomeTypeA 开头。下文开始将会统一使用这一规范。

1.7.2. 换行(段落)

读者可以注意到, 前文中的所有有效注释, 我都换了一行; 但是在 pkgsite 的页面展示中, 并没有发生换行。

实际上, 在注释中如果只是单纯的一个换行另写注释的话, 在页面是不会将其当作新的一段来看待的, GoDoc 的逻辑, 也仅仅渲染完这一行之后, 再加一个空格, 然后继续渲染下一行。

如果要在同一个注释块中新加一个段落, 那么我们需要插入一行空注释, 如下:

// SomeNewLine 只是用来展示如何在 GoDoc 中换行。 你看, 这就是新的一行了, 耶~✌️
func SomeNewLine() error {return nil}

1.7.3. 内嵌代码

如果有需要的话, 我们可以在注释中内嵌一小段代码, 代码会被独立为一个段落, 并且使用等宽字符展示。比如下面的一个例子:

// IntsElem 用于不 panic 地从一个 int 切片中读取元素, 并且返回值和实际在切片中的位置。
 不论是任何情况, 如果切片长为 0, 则 actual Index 返回 -1.
 根据参数 index 可以有几种情况:
 - 零值, 则直接取切片的第一个值
 - 正值, 则从切片 0 位置开始, 如果遇到切片结束了, 那么就循环从头开始数
 - 负值, 则表示逆序, 此时则循环从切片的最后一个值开始数
 负值的例子:
    sli := []int{0, -1, -2, -3}
//    val, idx := IntsElem(sli, -2)
 返回得 val = -2, idx = 2func IntsElem(ints []int, index int) (value, actualIndex int) {    // ......}

总结: 在注释块中, 如果部分注释行符合以下标准之一, 则视为代码块:

  • 注释行以制表符 \t 开头。
  • 注释行以以多于一个空格(包括制表符)开头。

普通注释和代码块之间可以不用专门的空注释行, 但个人建议还是加上比较好。

1.8. Overview 部分

在 Documentation 中的 Overview 部分, 是整个 package 的说明, 这种类型的注释, 被称为"包注释"。包注释是写在 go 文件最开始的 package xxx 上面。虽然 GoDoc 没有限制、但是 Go 官方建议包注释应当以// Package xxx 开头作为文本的主语。

如果在一个 package 中, 有多个文件都包含了包注释, 那么 GoDoc 会按照文件的字典序, 依次展示这些文件中的包注释。但这样可能会带来混乱, 因此一个 package 我们应当只在一个文件中写包注释。

一般而言, 我们可以选择以下的文件写包注释:

  • 很多 package 下面会有一个与 package 名称同名的 xxx.go 文件, 那我们可以统一就在这个文件里写包注释, 比如这样: (https://github.com/Andrew-M-C/go.jsonvalue/blob/v1.2.0/jsonvalue.go#L1)
  • 如果 xxx.go 文件本身承载了较多代码, 或者是包注释比较长, 那么我们可以专门开一个 doc.go 文件, 用来写包注释, 比如这样: (https://github.com/Andrew-M-C/go.jsonvalue/blob/v1.0.0/doc.go#L1)

1.9. 弃用代码声明

Go 所使用的版本号是 vX.Y.Z 的模式, 按照官方的思想, 每当 package 升级时, 尽量不要升级大版本 X 值, 这也同时代表着, 本次升级是完全向前兼容的。但是实际上, 我们在做一些小版本或中版本升级时, 有些函数/类型可能不再推荐使用。此时, GoDoc 提供了一个关键字 Deprecated:, 作为整个注释块的第一个单词, 比如我们可以这么写:

// Deprecated: ElemAt 这个函数弃用, 后续请迁移到 IntsElem 函数中。
func ElemAt(ints []int, index int) int {    // ......
}

针对 deprecated 的内容, pkgsite 一方面会在目录中标识出来:

此外, 在正文中, 也会刻意用灰色字体低调展示, 并且隐藏注释正文, 需要点开才能显示:

1.10. 代码示例文档

读者如果看我 jsonvalue 的文档 (https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue#Set.At), 在 At() 函数下, 除了上文提到的文档正文之外, 还有五个代码示例:

那么, 文档中的代码示例又应该如何写呢?

首先, 我们应该新建至少一个文件, 专门用来存放示例代码。比如我就把示例代码写在了 example_jsonvalue_test.go(https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go) 文件中。这个文件的 package 名不得与当前包名相同, 而应该命名为包名_test 的格式。

此外, 需要注意的是, 示例代码文件也属于单元测试文件的内容, 当执行 go test 的时候, 示例文件也会纳入测试逻辑中。

1.10.1. 示例代码的声明

如何声明一个示例代码, 这里我举两个例子。首先是在 At() 函数下名为"Example (1)"的示例。在代码 (https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go#L112) 中, 我把这个函数命名为:

func ExampleSet_At_1() {    ......}

这个函数命名有几个部分:

另外, 示例代码中应该包含标准输出内容, 这样便于读者了解执行情况。标准输出内容在函数内的最后, 采用//Output: 单独起一行开头, 剩下的每一行标准输出写一行注释。

相对应地, 如果你想要给(不属于任何一个类型的)函数写示例的话, 则去掉上文中关于"类型"的字段; 如果你不需要示例的额外说明符, 则去掉"额外说明"字段。比如说, 我给类型 Opt 写的示例 (https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue#example-Opt) 就只有一个, 在代码 (https://github.com/Andrew-M-C/go.jsonvalue/blob/master/example_jsonvalue_test.go#L43) 中, 只有一行:

func ExampleOpt() {    ........}

甚至连示例说明都没有。

如果一个元素包含多个例子, 那么 godoc 会按照字母序对示例及其相应的说明排序。这也就是为什么我干脆在 At() 函数中, 示例标为一二三四五的原因, 因为这是我希望读者阅读示例的顺序。

1.10.2. 在官网上发布 GoDoc

好了, 当你写好了自己的 GoDoc 之后, 总不是自己看自己自娱自乐吧, 总归是要发布出来给大家看的。

其实发布也很简单: 当你将包含了 godoc 的代码 push 之后(比如发布到 github 上), 就可以在浏览器中输入 https://pkg.go.dev/${package 路径名}。比如 jsonvalue 的 Github 路径(也等同于 import 路径)为 github.com/Andrew-M-C/go.jsonvalue, 因此输入 (https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue)。

如果这是该页面第一次进入, 那么 pkg.go.dev 会首先获取、解析和更新代码仓库中的文档内容, 并且格式化之后展示。在 pkg.go.dev 中, 如果能够找到 package 的最新的 tag 版本, 那么会列出 tag(而不是主干分支)上的 GoDoc。

接下来更重要的是, 把这份官网 GoDoc 的链接, 附到你自己的 README 中。我们可以进入 pkg.go.dev 的徽章生成页 (‍‍‍‍‍‍‍‍https://pkg.go.dev/badge/‍)

输入仓库地址就可以看到相应的徽标的链接了。有 html 和 markdown 格式任君选择。

作为 Gopher, 你知道 Go 的注释即文档应该怎么写吗相关推荐

  1. javadoc文档的生成方法_Cocoa 代码注释与文档生成

    Cocoa 代码注释与文档生成 本文的文档规范部分的内容参考自:NSHipster 的 Swift Documentation 作者 & Nate Cook 本文知识目录 背景 曾经以为好的代 ...

  2. java 注释之文档标签

    java 注释之文档标签 @see :引用其他类 @see标签允许用户引用其他类的文档.javadoc会在其生成的HTML文件中,通过@see标签链接到其他的文档,格式如下 @see classnam ...

  3. Java注释 link_Java 文档注释

    Java只是三种注释方式.前两种分别是// 和/* */,第三种被称作说明注释,它以/** 开始,以 */结束. 说明注释允许你在程序中嵌入关于程序的信息.你可以使用javadoc工具软件来生成信息, ...

  4. 基于文档注释接口文档生成工具(代码0侵入附源码)

    本文主要分享一个基于个人兴趣,旨在提高工作效率,开发了一个基于文档注释,接口文档生成工具,欢迎大佬指点. 源码以及使用demo地址 :传送门 1.前置介绍 1.1前世 现在大多数项目都走向了前后端分离 ...

  5. C# 代码注释规范文档

    C# 提供一种机制,使程序员可以使用含有 XML 文本的特殊注释语法为他们的代码编写文档.在源代码文件中,具有某种格式的注释可用于指导某个工具根据这些注释和它们后面的源代码元素生成 XML.使用这类语 ...

  6. 如何写Java文档注释(Java Doc Comments)

    本文翻译自How to Write Doc Comments for the Javadoc Tool,但是精简了一些私以为不重要的东西 本文不讨论如何使用javadoc工具自动生成文档的方法,而是主 ...

  7. java注释【单行注释,多行注释,文档注释】

    文章目录 一.java注释类型 二.详细操作 代码 生成文档 到生成的目录下面查看 一.java注释类型 单行注释 多行注释 文档注释 注意:注释过的语句不会被java虚拟机执行 二.详细操作 1.单 ...

  8. IDEA JAVA文档注释和方法注释模板

    IDEA JAVA文档注释和方法注释模板 文档注释 #if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${ ...

  9. 非零基础自学Golang 第15章 Go命令行工具 15.4 注释文档(doc)

    非零基础自学Golang 文章目录 非零基础自学Golang 第15章 Go命令行工具 15.4 注释文档(doc) 第15章 Go命令行工具 15.4 注释文档(doc) Go语言文档工具go do ...

最新文章

  1. 鸟哥Linux私房菜知识点总结3到5章
  2. swift3.0 post Json解析
  3. 翻译:用户变量(User-Defined Variable)(已提交到MariaDB官方手册)
  4. @requestbody和@requestparam作用
  5. 三维重建中旋转矩阵与平移矩阵思想误区(转载)
  6. php ora-12154,ORA-12154 和 TNS-03505 监听错误的解决方法
  7. 如何在矩池云上查看cudnn版本
  8. r语言的rmd文件转换成html,.Rmd文件转化为PDF报告
  9. python的浮点数占 个字节_Python的浮点数占 个字节。_学小易找答案
  10. 清风数学建模学习笔记——层次分析法(AHP)
  11. 关于flash分区打印信息jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985
  12. mmClassification学习笔记
  13. [python]一个特别好的学习python网站
  14. CentOS.7卸载与安装Nvidia Driver
  15. 什么是802.11ax(Wi-Fi 6)
  16. Mysql学习记录【Mysql字符集】
  17. Optics Bridge:Celo <-> 以太坊
  18. python使用XPATH爬取电影票房
  19. python获取期权行情包括k线,tick,greeks分时等数据
  20. ERP 软件项目验收流程

热门文章

  1. IR-CUT选择须知
  2. ASP.NET Razor 简介
  3. 这一年,熬过许多夜,也有些许收获 | 2022年终总结
  4. emoji表情mysql处理_Mysql Emoji表情处理
  5. python里row是什么意思_row python
  6. python+twilio实现打电话和发短信功能
  7. shell正则表达式及一些排序命令(sort、uniq、tr)
  8. word保存为html不压缩图片大小,教你怎样从word中提取图片以及缩小图片大小
  9. 惯性导航原理(2):导航基础知识
  10. twitter加载很慢_我很高兴加入Twitter的6个理由