Skip to content

Commit c6bb1e6

Browse files
committed
add posts.
0 parents  commit c6bb1e6

File tree

335 files changed

+12328
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

335 files changed

+12328
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "themes/hugo-book"]
2+
path = themes/hugo-book
3+
url = https://github.com/alex-shpak/hugo-book

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Go 语言进阶之旅

archetypes/default.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: "{{ replace .Name "-" " " | title }}"
3+
date: {{ .Date }}
4+
draft: true
5+
---
6+

config.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
baseURL = "http://example.org/"
2+
languageCode = "zh-cn"
3+
title = "Go 语言设计哲学"
4+
theme = "book"
5+
6+
[params]
7+
BookToC = true
8+
BookSection = 'posts'
9+
BookMenuBundle = '/menu'

content/_index.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Go 语言设计哲学
2+
3+
大家好,我是煎鱼。
4+
5+
## 学习和交流
6+
7+
基本会先更新在公众号,再同步到站点上。若想一起学习,欢迎加我的微信:cJY0728。
8+
9+
也可以关注公众号:
10+
11+
![image](https://image.eddycjy.com/6c2b084165ecce1f81bc5e07c3f9a6c7.jpg)
12+
13+
## 批评和建议
14+
15+
如果有任何建议或疑问欢迎随时在本书的评论区与我交流,会尽量在 1-2 天内回复你。

content/menu/index.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
headless: true
3+
---
4+
- 第一章:设计之道
5+
- 1.1 开发 Go 的原因
6+
- 第二章:语言特性
7+
- [2.1 类和继承]({{< relref "/posts/objects.md" >}})
8+
- [2.2 可重入锁]({{< relref "/posts/repeat-mutex.md" >}})
9+
- [2.3 并发读写]({{< relref "/posts/concurrent-mapslice.md" >}})
10+
- [2.4 函数重载和缺省参数]({{< relref "/posts/func-overloading-defalut.md" >}})
11+
- [2.5 高级注解]({{< relref "/posts/annotation.md" >}})
12+
- [2.6 三元运算符]({{< relref "/posts/operator.md" >}})
13+
- 第三章:设计思考
14+
- [3.1 类型后置]({{< relref "/posts/type-after.md" >}})
15+
- [3.2 循环引用]({{< relref "/posts/cyclic-import.md" >}})
16+
- 3.3 泛型设计
17+
- [3.4 错误处理]({{< relref "/posts/error-handler.md" >}})
18+
- 第四章:奇怪关联
19+
- 4.1 Go 和 Golang

content/posts/annotation.md

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
---
2+
title: "高级注解"
3+
type: docs
4+
---
5+
6+
# 高级注解
7+
8+
作为一位 Go 程序员,你会发现身边的同事大多都拥有其他语言的编写经验。那势必就会遇到一点,要把新学到的知识和以前的知识建立连接。
9+
10+
![image](../../../images/tree.png)
11+
12+
特殊在于,Go 有些特性是其他语言有,他没有的。最经典的就是 N 位 Java 同学寻找 Go 语言的注解在哪里,总要解释。
13+
14+
为此,今天煎鱼就带大家了解一下 Go 语言的注解的使用和情况。
15+
16+
## 什么是注解
17+
18+
### 了解历史
19+
20+
注解(Annotation)最早出现自何处,翻了一圈并没有找到。但可以明确,在注解的使用中,Java 注解最为经典,为了便于理解,因此我们基于 Java 做初步的注解理解。
21+
22+
![image](../../../images/java-annotation.png)
23+
24+
在 2002 年,JSR-175 提出了 《[A Metadata Facility for the Java Programming Language](https://jcp.org/en/jsr/detail?id=175)》,也就是为 Java 编程语言提供元数据工具。
25+
26+
这就是现在使用最广泛地注解(Annotation)的来源。
27+
示例如下:
28+
29+
```golang
30+
// @annotation1
31+
// @annotation2
32+
func Hello() string {
33+
return ""
34+
}
35+
```
36+
37+
在格式上均以 “@” 作为注解标识来使用。
38+
39+
### 注解例子
40+
41+
摘抄自 @wikipedia 的一个注解例子:
42+
43+
```java
44+
//等同于 @Edible(value = true)
45+
@Edible(true)
46+
Item item = new Carrot();
47+
48+
public @interface Edible {
49+
boolean value() default false;
50+
}
51+
52+
@Author(first = "Oompah", last = "Loompah")
53+
Book book = new Book();
54+
55+
public @interface Author {
56+
String first();
57+
String last();
58+
}
59+
60+
// 该标注可以在运行时通过反射访问。
61+
@Retention(RetentionPolicy.RUNTIME)
62+
// 该标注只用于类内方法。
63+
@Target({ElementType.METHOD})
64+
public @interface Tweezable {
65+
}
66+
67+
```
68+
69+
在上述例子中,通过注解去做了一系列的定义、声明、赋值等。若是对语言既有注解不熟,或是做的比较复杂的注解,就会有一定的理解成本。
70+
71+
在业内也常常会说,**注解就是 “在源码上进行编码”**,注解的存在,有着明确的优缺点。你觉得呢?
72+
73+
## 注解的作用
74+
75+
在注解的的作用上,分为如下几点:
76+
1. 为编译器提供信息:注释可以被编译器用来检测错误或支持警告。
77+
2. 编译时和部署时处理:软件工具可以处理注释信息以生成代码、XML文件等。
78+
3. 运行时处理:有些注解可以在运行时检查,并用于其他用途。
79+
80+
## Go 注解在哪里
81+
82+
### 现状
83+
84+
Go 语言本身并没有原生支持强大的注解,仅限于以下两种:
85+
- 编译时生成:go:generate
86+
- 编译时约束:go:build
87+
88+
但这先按不足以作为一个函数注解来使用,也无法形成像 Python 那样的装饰器行为。
89+
90+
### 为什么不支持
91+
92+
Go issues 上有人提过类似的提案:
93+
94+
![image](../../../images/go2-decorator.png)
95+
96+
97+
Go Contributor @ianlancetaylor 给出了明确的答复,Go在设计上更倾向于明确的、显式的编程风格。
98+
99+
思考的优缺点如下:
100+
- 优势:不知道 Go 能从添加装饰器中得到什么好处,没能在 issues 上明确论证。
101+
- 缺点:是明确的,会存在意外设置的情况。
102+
103+
因如下原因,没有接受注解:
104+
- 对比现有代码方法,这种装饰器的新的方法没有提供比现有方法更多的优势,大到足矣推翻原有的设计思路。
105+
- 社区内的投票,支持的也很少(基于表情符号的投票),用户反馈不多。
106+
107+
可能有小伙伴会说了,有注解做装饰器了,代码会简洁不少。
108+
109+
对此 Go 团队的态度很明确:
110+
111+
![image](../../../images/go-annoation-lan.png)
112+
113+
Go 认为**可读性更重要**,如果只是额外多写一点代码,在权衡后,还是可以接受的。
114+
115+
## 用 Go 实现注解
116+
117+
虽然 Go 语言官方没有原生的完整支持,但开源社区中也有小伙伴已经放出了大招,借助各项周边工具和库来实现特定的函数注解功能。
118+
119+
120+
GitHub 项目分别如下:
121+
- [MarcGrol/golangAnnotations](github.com/MarcGrol/golangAnnotations)
122+
- [u2takey/go-annotation](https://github.com/u2takey/go-annotation)
123+
124+
使用示例如下:
125+
126+
```golang
127+
package tourdefrance
128+
129+
//go:generate golangAnnotations -input-dir .
130+
131+
// @RestService( path = "/api/tour" )
132+
type TourService struct{}
133+
134+
type EtappeResult struct{ ... }
135+
136+
// @RestOperation( method = "PUT", path = "/{year}/etappe/{etappeUid}" )
137+
func (ts *TourService) addEtappeResults(c context.Context, year int, etappeUid string, results EtappeResult) error {
138+
return nil
139+
}
140+
```
141+
142+
对 Go 注解的使用感兴趣的小伙伴可以自行查阅使用手册。
143+
144+
我们更多的关心,Go 原生都没支持,那么开源库都是如何实现的呢?在此我们借助 [MarcGrol/golangAnnotations](github.com/MarcGrol/golangAnnotations) 项目所提供的思路来讲解。
145+
146+
分为三个步骤:
147+
1. 解析代码。
148+
2. 模板处理。
149+
3. 生成代码。
150+
151+
### 解析 AST
152+
153+
首先,我们需要用用 go/ast 标准库获取代码所生成的 AST Tree 中需要的内容和结构。
154+
155+
示例代码如下:
156+
157+
```shell
158+
parsedSources := ParsedSources{
159+
PackageName: "tourdefrance",
160+
Structs: []model.Struct{
161+
{
162+
DocLines: []string{"// @RestService( path = "/api/tour" )"},
163+
Name: "TourService",
164+
Operations: []model.Operation{
165+
{
166+
DocLines: []string{"// @RestOperation( method = "PUT", path = "/{year}/etappe/{etappeUid}"},
167+
...
168+
},
169+
},
170+
},
171+
},
172+
}
173+
```
174+
我们可以看到,在 AST Tree 中能够获取到在示例代码中所定义的注解内容,我们就可以依据此去做很多奇奇怪怪的事情了。
175+
176+
### 模板生成
177+
178+
紧接着,在知道了注解的输入是什么后,我们只需要根据实际情况,编写对应的模板生成器 code-generator 就可以了。
179+
180+
我们会基于 text/template 标准库来实现,比较经典的像是 [kubernetes/code-generator](https://github.com/kubernetes/code-generator) 是一个可以参考的实现。
181+
182+
代码实现完毕后,将其编译成 go plugin,便于我们在下一步调用就可以了。
183+
184+
### 代码生成
185+
186+
最后,万事俱备只欠东风。差的就是告诉工具,哪些 Go 文件中包含注解,需要我们去生成的。
187+
188+
这时候我们可以使用 `//go:generate` 在 Go 文件声明。就像前面的项目中所说的:
189+
190+
```
191+
//go:generate golangAnnotations -input-dir .
192+
```
193+
194+
声明该 Go 文件需要生成,并调用前面编写好的 golangAnnotations 二进制文件,就可以实现基本的 Go 注解生成了。
195+
196+
## 总结
197+
198+
我们介绍了注解(Annotation)的历史背景。同时我们针对 Go 语言目前原生的注解支持情况进行了说明。
199+
200+
也面向为什么 Go 没有像 Java 那样支持强大的注解进行了基于 Go 官方团队的原因解释。如果希望在 Go 实现注解的,也提供了相应的开源技术方案。
201+
202+
你觉得 Go 语言是否需要有强大的注解支持?

0 commit comments

Comments
 (0)