当前位置: 首页 > 科技观察

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

时间:2023-03-12 12:53:37 科技观察

大家好,我是炸鱼。作为一名Go程序员,你会发现身边的同事大多都有其他语言的编写经验。那么必然会有一个点,把新学的知识和以前的知识建立联系。图片来自网络,特别之处在于Go有一些其他语言有,而它没有的特性。最经典的就是N个Java同学在找Go语言的注解在哪里,总要解释。为此,今天剑鱼就带大家了解一下Go语言中注解的使用和情况。什么是注解?知道历史注解(Annotation)最早出现在什么地方,但翻来覆去也没找到。但是很显然,在注解的使用上,Java注解是最经典的。为了便于理解,我们对基于Java的注解做一个初步的了解。2002年,JSR-175提出《A Metadata Facility for the Java Programming Language》,为Java编程语言提供元数据工具。这就是使用最广泛的注解(Annotation)的来源。示例如下://@annotation1//@annotation2funcHello()string{return""}作为注解标记,格式为“@”。注解示例摘自@wikipedia的一个注解示例://等同于@Edible(value=true)@Edible(true)Itemitem=newCarrot();public@interfaceEdible{booleanvalue()defaultfalse;}@Author(first="Oompah",last="Loompah")Bookbook=newBook();public@interfaceAuthor{Stringfirst();Stringlast();}//运行时可以通过反射访问这个注解。@Retention(RetentionPolicy.RUNTIME)//这个注解只用于类内的方法。@Target({ElementType.METHOD})public@interfaceTweezable{}在上面的例子中,通过注解进行了一系列的定义、声明、赋值等。如果不熟悉语言注解,或者做比较复杂的注解,都会有一定的理解成本。业内常说注解是“在源代码上编码”。注释的存在有明显的优点和缺点。你怎么认为?注解的作用从注解的作用来看,分为以下几点:为编??译器提供信息:编译器可以使用注解来检测错误或支持警告。编译时和部署时处理:软件工具可以处理注释信息以生成代码、XML文件等。运行时处理:一些注释可以在运行时检查并用于其他目的。Go注解在哪里?Go语言本身并不支持强大的注解,仅限于以下两种:编译时生成:go:generate编译时约束:go:build但这不足以用作函数注解,并且没有像在Python中那样形成装饰器行为的方法。为什么不支持Go问题有人提出了类似的建议:GoContributor@ianlancetaylor给出了明确的回答,Go在设计上更倾向于清晰明确的编程风格。思路的优缺点如下:优点:不知道Go加装饰器能得到什么好处,在issues中也无法清楚地展示。缺点:很明显会有意外设置。注释不被接受的原因如下:与现有代码方法相比,该装饰器的新方法并没有提供比现有方法更多的优势,并且大到足以推翻原有的设计思路。社区投票很少(表情投票),用户反馈不多。可能有朋友会说,有注解作为装饰器,代码会简单很多。Go团队的态度很明确:Go认为可读性更重要。如果只是多写一点代码,权衡之后,还是可以接受的。用Go实现注解虽然Go官方语言并没有完整的原生支持,但是开源社区的一些小伙伴已经放出了大招,借助各种周边工具和库来实现特定的功能注解。GitHub项目如下:MarcGrol/golangAnnotationsu2takey/go-annotation使用示例如下:packagetourdefrance//go:generategolangAnnotations-input-dir.//@RestService(path="/api/tour")typeTourServicestruct{}typeEtappeResultstruct{...}//@RestOperation(method="PUT",path="/{year}/etappe/{etappeUid}")func(ts*TourService)addEtappeResults(ccontext.Context,yearint,etappeUidstring,resultsEtappeResult)error{returnnil}pair有兴趣使用Go注解的朋友可以自行查阅手册。我们更关心。Go本身不支持,那么开源库是如何实现的呢?这里我们使用MarcGrol/golangAnnotations项目提供的思路来进行讲解。分为三步:解析代码。模板处理。生成代码。解析AST首先,我们需要使用go/ast标准库,在代码生成的ASTTree中获取需要的内容和结构。示例代码如下:parsedSources:=ParsedSources{PackageName:"tourdefrance",Structs:[]model.Struct{{DocLines:[]string{"//@RestService(path="/api/tour")"},Name:"TourService",Operations:[]model.Operation{{DocLines:[]string{"//@RestOperation(method="PUT",path="/{year}/etappe/{etappeUid}"},...},},},},}我们可以看到示例代码中定义的注解内容在ASTTree中是可以获取到的,我们可以基于它做很多奇奇怪怪的事情,模板生成如下知道后注解的输入是什么,我们只需要根据实际情况编写对应的模板生成器code-generator即可,我们基于text/template标准库来实现,比较经典的比如kubernetes/code-generator是一个可以参考的实现,代码实现后,编译成goplugin,方便我们下一步调用,代码生成结束,一切就绪,唯一的事情就是告诉工具哪些Go文件包含注解,我们需要生成这些注解。这时候我们可以使用//go:generate在Go文件中声明。在之前的项目中提到过://go:generategolangAnnotations-input-dir。声明Go文件需要Generate,调用之前编写的golangAnnotations二进制文件,实现基本的Go注解生成。总结今天这篇文章,我们介绍了注解(Annotation)的历史背景。同时针对目前Go语言原生注解的支持情况进行说明。这也解释了为什么Go不像Java那样支持强大的注解。基于官方Go团队的解释。如果想在Go中实现注解,也提供了相应的开源技术方案。你觉得Go语言像Java一样需要注解支持吗?