怎么知道某个 API 是在哪个 Go 版本添加的?这个功能如何实现的

开发 后端
因为 Go 的兼容性做的很好,很多人不太关心 Go 的具体版本。然而有时候可能会涉及到版本的问题,比如你想使用 strings.Builder,Go 版本就必须 >= 1.10,但以下代码在 Go1.10 却编译不通过。

[[380645]]

 大家好,我是站长 polarisxu。

因为 Go 的兼容性做的很好,很多人不太关心 Go 的具体版本。然而有时候可能会涉及到版本的问题,比如你想使用 strings.Builder,Go 版本就必须 >= 1.10,但以下代码在 Go1.10 却编译不通过。

  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.   "strings" 
  6.  
  7. func main() { 
  8.   var b strings.Builder 
  9.   b.WriteString("polarisxu"
  10.   fmt.Println(b.Cap()) 

编译会报错:

  1. $ go version 
  2. go version go1.10.8 darwin/amd64 
  3. $ go run main.go 
  4. # command-line-arguments 
  5. ./main.go:11:15: b.Cap undefined (type strings.Builder has no field or method Cap) 

提示 strings.Builder 类型没有 Cap 字段或方法。

所以,你知道标准库中哪个 API 是什么版本引入的吗?或者更实际的是,我当前的版本是否能使用某个 API。

01 常见的两种方式

在 Go 官网有最新稳定版本的标准库文档。从 Go1.11 版本开始,在标准库中,每个类型、函数或方法有加入的版本信息,如果没有,表示 Go1.0 就有了,具体 issue 见:https://github.com/golang/go/issues/5778。但目前常量和变量没有版本信息,具体 issue 见:https://github.com/golang/go/issues/29204。

第二种方法,不是看具体某个 API 对应的版本,而是至少知晓,你当前使用的 Go 版本有没有某个 API,这就是 pkg.go.dev,具体通过这个网站 https://pkg.go.dev/std?tab=versions 选择你对应的版本,然后查找是否有对应的 API。

当然了,你使用 GoLand 之类的编辑器,某个 API 是否有,它会自动提示。

02 标准库显示版本是如何实现的

保持好奇心很重要,这是求知的动力之一。看到官网标准库显示了版本信息,我就想看看它是怎么实现的。

怎么查找实现的代码?

我的第一反应是看标准库注释里有没有写。

  1. // A Builder is used to efficiently build a string using Write methods. 
  2. // It minimizes memory copying. The zero value is ready to use. 
  3. // Do not copy a non-zero Builder. 
  4. type Builder struct { 
  5.  addr *Builder // of receiver, to detect copies by value 
  6.  buf  []byte 

没有看到任何版本相关信息。这时你会如何查找?

我的方式是这样的。

1)在页面审查元素,看到 1.10 节点。

2)Go 官网源码在这里:https://github.com/golang/website,在该源码中搜索 Added in,找到了 package.html 模板文件。

3)上图中, $since 变量代表了 Go 版本,而它是通过 since 函数得到的:`{{.PDoc.ImportPath}}`,很显然这是一个自定义模板函数,因此查找它。website 项目没有找到,因此到 tools[1] 项目去找:因为 godoc 在这个项目中。

通过这个可以找到 sinceVersionFunc 所在文件:versions.go,然后就能找到如下的代码:

  1. // InitVersionInfo parses the $GOROOT/api/go*.txt API definition files to discover 
  2. // which API features were added in which Go releases. 
  3. func (c *Corpus) InitVersionInfo() { 
  4.  var err error 
  5.  c.pkgAPIInfo, err = parsePackageAPIInfo() 
  6.  if err != nil { 
  7.   // TODO: consider making this fatal, after the Go 1.11 cycle. 
  8.   log.Printf("godoc: error parsing API version files: %v", err) 
  9.  } 
  10.  
  11. func parsePackageAPIInfo() (apiVersions, error) { 
  12.  var apiGlob string 
  13.  if os.Getenv("GOROOT") == "" { 
  14.   apiGlob = filepath.Join(build.Default.GOROOT, "api""go*.txt"
  15.  } else { 
  16.   apiGlob = filepath.Join(os.Getenv("GOROOT"), "api""go*.txt"
  17.  } 
  18.  
  19.  files, err := filepath.Glob(apiGlob) 
  20.  if err != nil { 
  21.   return nil, err 
  22.  } 
  23.  
  24.  vp := new(versionParser) 
  25.  for _, f := range files { 
  26.   if err := vp.parseFile(f); err != nil { 
  27.    return nil, err 
  28.   } 
  29.  } 
  30.  return vp.res, nil 

通过以上代码可以看出来版本信息是通过读取 GOROOT 下 api/go*.txt 文件获取的。

api 目录下的这些文件维护了每个版本新增的内容。

最终从这些文件中读取的内容会用以下的类型表示:

  1. // pkgAPIVersions contains information about which version of Go added 
  2. // certain package symbols. 
  3. // 
  4. // Only things added after Go1 are tracked. Version strings are of the 
  5. // form "1.1""1.2", etc. 
  6. type pkgAPIVersions struct { 
  7.  typeSince   map[string]string            // "Server" -> "1.7" 
  8.  methodSince map[string]map[string]string // "*Server" ->"Shutdown"->1.8 
  9.  funcSince   map[string]string            // "NewServer" -> "1.7" 
  10.  fieldSince  map[string]map[string]string // "ClientTrace" -> "Got1xxResponse" -> "1.11" 

这里有类型、方法、函数和(类型)字段,但没有变量和常量,这也就是说变量和常量的版本号显示还未实现。

最后,在 website 项目的 main 函数中有这么一句:

  1. // Initialize the version info before readTemplates, which saves 
  2. // the map value in a method value. 
  3. corpus.InitVersionInfo() 

用于初始化版本信息。

03 总结

希望你平时生活、学习和工作过程中,能多一些好奇。本文是一个引子,内容不太重要,过程希望能够对你有所启发。当然,如果你计划学习学习 Go 语言官网的实现,也许本文的帮助会更大。

参考资料

[1]tools: https://github.com/golang/tools

本文转载自微信公众号「polarisxu」,可以通过以下二维码关注。转载本文请联系polarisxu公众号。

责任编辑:武晓燕 来源: polarisxu
相关推荐

2021-10-20 09:20:40

手机定位互联网位置服务

2020-12-08 09:25:41

死锁MySQL数据库

2018-07-05 11:05:10

2023-04-28 07:44:44

MyBatis查询SQL

2022-01-14 17:01:44

GoError结构

2022-01-07 07:59:14

Go语言Go Error

2023-08-10 08:00:42

令牌限流器计数器

2021-10-04 14:55:40

Windows 11Windows微软

2023-04-03 08:02:16

切片扩容GO

2023-03-07 08:00:12

netpollGo

2023-07-25 09:00:00

人工智能深度伪造视频

2022-01-10 11:33:17

Go测试软件

2024-02-21 09:46:58

2020-06-18 12:23:05

WiFi速度5G

2023-10-31 08:32:59

2016-02-01 09:24:24

Quora排行算法

2024-02-22 09:21:09

.NETActionOptions

2022-06-28 07:40:54

JVM线程开源

2012-12-10 15:12:43

2013-02-27 10:27:44

GitHub
点赞
收藏

51CTO技术栈公众号