Go:我有注解,Java:不,你没有!

开发 后端
作为一位 Go 程序员,你会发现身边的同事大多都拥有其他语言的编写经验。那势必就会遇到一点,要把新学到的知识和以前的知识建立连接。

[[429036]]

大家好,我是煎鱼。

作为一位 Go 程序员,你会发现身边的同事大多都拥有其他语言的编写经验。那势必就会遇到一点,要把新学到的知识和以前的知识建立连接。

[[429037]]

图来自网络

特殊在于,Go 有些特性是其他语言有,他没有的。最经典的就是 N 位 Java 同学寻找 Go 语言的注解在哪里,总要解释。

为此,今天煎鱼就带大家了解一下 Go 语言的注解的使用和情况。

什么是注解

了解历史

注解(Annotation)最早出现自何处,翻了一圈并没有找到。但可以明确,在注解的使用中,Java 注解最为经典,为了便于理解,因此我们基于 Java 做初步的注解理解。

在 2002 年,JSR-175 提出了 《A Metadata Facility for the Java Programming Language》,也就是为 Java 编程语言提供元数据工具。

这就是现在使用最广泛地注解(Annotation)的来源。示例如下:

  1. // @annotation1 
  2. // @annotation2 
  3. func Hello() string { 
  4.         return "" 

在格式上均以 “@” 作为注解标识来使用。

注解例子

摘抄自 @wikipedia 的一个注解例子:

  1. //等同于 @Edible(value = true
  2. @Edible(true
  3. Item item = new Carrot(); 
  4.  
  5. public @interface Edible { 
  6.   boolean value() default false
  7.  
  8. @Author(first = "Oompah"last = "Loompah"
  9. Book book = new Book(); 
  10.  
  11. public @interface Author { 
  12.   String first(); 
  13.   String last(); 
  14.  
  15. // 该标注可以在运行时通过反射访问。 
  16. @Retention(RetentionPolicy.RUNTIME)  
  17. // 该标注只用于类内方法。 
  18. @Target({ElementType.METHOD}) 
  19. public @interface Tweezable { 

在上述例子中,通过注解去做了一系列的定义、声明、赋值等。若是对语言既有注解不熟,或是做的比较复杂的注解,就会有一定的理解成本。

在业内也常常会说,注解就是 “在源码上进行编码”,注解的存在,有着明确的优缺点。你觉得呢?

注解的作用

在注解的的作用上,分为如下几点:

为编译器提供信息:注释可以被编译器用来检测错误或支持警告。

编译时和部署时处理:软件工具可以处理注释信息以生成代码、XML文件等。

运行时处理:有些注解可以在运行时检查,并用于其他用途。

Go 注解在哪里

现状

Go 语言本身并没有原生支持强大的注解,仅限于以下两种:

  • 编译时生成:go:generate
  • 编译时约束:go:build

但这先按不足以作为一个函数注解来使用,也无法形成像 Python 那样的装饰器行为。

为什么不支持

Go issues 上有人提过类似的提案:

Go Contributor @ianlancetaylor 给出了明确的答复,Go 在设计上更倾向于明确的、显式的编程风格。

思考的优缺点如下:

  • 优势:不知道 Go 能从添加装饰器中得到什么好处,没能在 issues 上明确论证。
  • 缺点:是明确的,会存在意外设置的情况。

因如下原因,没有接受注解:

  • 对比现有代码方法,这种装饰器的新的方法没有提供比现有方法更多的优势,大到足矣推翻原有的设计思路。
  • 社区内的投票,支持的也很少(基于表情符号的投票),用户反馈不多。

可能有小伙伴会说了,有注解做装饰器了,代码会简洁不少。

对此 Go 团队的态度很明确:

Go 认为可读性更重要,如果只是额外多写一点代码,在权衡后,还是可以接受的。

用 Go 实现注解

虽然 Go 语言官方没有原生的完整支持,但开源社区中也有小伙伴已经放出了大招,借助各项周边工具和库来实现特定的函数注解功能。

GitHub 项目分别如下:

  • MarcGrol/golangAnnotations
  • u2takey/go-annotation

使用示例如下:

  1. package tourdefrance 
  2.  
  3. //go:generate golangAnnotations -input-dir . 
  4.  
  5. // @RestService( path = "/api/tour" ) 
  6. type TourService struct{} 
  7.  
  8. type EtappeResult struct{ ... } 
  9.  
  10. // @RestOperation( method = "PUT", path = "/{year}/etappe/{etappeUid}" ) 
  11. func (ts *TourService) addEtappeResults(c context.Context, year int, etappeUid string, results EtappeResult) error { 
  12.  return nil 

对 Go 注解的使用感兴趣的小伙伴可以自行查阅使用手册。

我们更多的关心,Go 原生都没支持,那么开源库都是如何实现的呢?在此我们借助 MarcGrol/golangAnnotations 项目所提供的思路来讲解。

分为三个步骤:

  • 解析代码。
  • 模板处理。
  • 生成代码。

解析 AST

首先,我们需要用用 go/ast 标准库获取代码所生成的 AST Tree 中需要的内容和结构。

示例代码如下:

  1. parsedSources := ParsedSources{ 
  2.     PackageName: "tourdefrance"
  3.     Structs:     []model.Struct{ 
  4.         { 
  5.             DocLines:   []string{"// @RestService( path = "/api/tour" )"}, 
  6.             Name:       "TourService"
  7.             Operations: []model.Operation{ 
  8.                 { 
  9.                    DocLines:   []string{"// @RestOperation( method = "PUT", path = "/{year}/etappe/{etappeUid}"}, 
  10.                    ... 
  11.                 }, 
  12.             }, 
  13.         }, 
  14.     }, 

我们可以看到,在 AST Tree 中能够获取到在示例代码中所定义的注解内容,我们就可以依据此去做很多奇奇怪怪的事情了。

模板生成

紧接着,在知道了注解的输入是什么后,我们只需要根据实际情况,编写对应的模板生成器 code-generator 就可以了。

我们会基于 text/template 标准库来实现,比较经典的像是 kubernetes/code-generator 是一个可以参考的实现。

代码实现完毕后,将其编译成 go plugin,便于我们在下一步调用就可以了。

代码生成

最后,万事俱备只欠东风。差的就是告诉工具,哪些 Go 文件中包含注解,需要我们去生成的。

这时候我们可以使用 //go:generate 在 Go 文件声明。就像前面的项目中所说的:

  1. //go:generate golangAnnotations -input-dir . 

声明该 Go 文件需要生成,并调用前面编写好的 golangAnnotations 二进制文件,就可以实现基本的 Go 注解生成了。

总结

今天在这篇文章中,我们介绍了注解(Annotation)的历史背景。同时我们针对 Go 语言目前原生的注解支持情况进行了说明。

也面向为什么 Go 没有像 Java 那样支持强大的注解进行了基于 Go 官方团队的原因解释。如果希望在 Go 实现注解的,也提供了相应的开源技术方案。

你觉得 Go 语言是否需要像和 Java 一样的注解支持呢?

 

责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2020-12-24 18:46:11

Java序列化编程语言

2020-04-01 17:50:02

Python编程语言

2022-05-11 09:04:50

Go函数数组

2009-07-27 14:11:22

硅谷动力

2022-03-15 07:58:31

SQL风险字符串

2016-12-28 14:51:46

大数据应用

2023-06-30 08:26:24

Java注解Java程序元素

2022-12-28 11:44:19

用户画像互联网用户信息

2021-06-09 11:28:04

用户画像标签

2023-11-01 11:34:40

用户画像企业

2021-09-08 18:35:31

系统调试日志

2020-05-25 10:05:26

Python 开发程序员

2022-11-11 08:31:39

Java注解注解类

2021-07-04 14:19:03

RabbitMQ消息转换

2024-01-18 09:38:00

Java注解JDK5

2020-04-20 13:43:59

黑客联网攻击

2022-01-12 18:20:36

GoJava开发

2015-07-03 09:37:21

程序员外包公司

2020-05-19 21:06:17

任正非华为员工

2017-09-22 15:25:40

Go语言其他语言错误处理
点赞
收藏

51CTO技术栈公众号