-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
295 lines (141 loc) · 422 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>golang-09-map</title>
<link href="/2024/08/13/golang-09-map/"/>
<url>/2024/08/13/golang-09-map/</url>
<content type="html"><![CDATA[<h1 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h1><p>map是一种<code>key:value</code>键值对的数据结构容器。map内部实现是哈希表(<code>hash</code>)。</p><p>map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。</p><p>map是引用类型的。</p><h2 id="map的语法格式"><a href="#map的语法格式" class="headerlink" title="map的语法格式"></a>map的语法格式</h2><p>可以使用内建函数 make 也可以使用 map 关键字来定义 map</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">/* 声明变量,默认 map 是 nil */</span><br><span class="hljs-keyword">var</span> map_variable <span class="hljs-keyword">map</span>[key_data_type]value_data_type<br><span class="hljs-comment">/* 使用 make 函数 */</span><br>map_variable = <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[key_data_type]value_data_type)<br></code></pre></td></tr></table></figure><p><code>map_variable</code>:map变量名称</p><p><code>key_data_type</code>:key的数据类型</p><p><code>value_data_type</code>:值得数据类型</p><p><strong>实例</strong></p><p>下面声明一个保存个人信息的map</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>m1 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br>m1[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br>m1[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br>m1[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><br>fmt.Printf(<span class="hljs-string">"m1: %v\n"</span>, m1)<br><br>m2 := <span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>{<br><span class="hljs-string">"name"</span>: <span class="hljs-string">"kite"</span>,<br><span class="hljs-string">"age"</span>: <span class="hljs-string">"20"</span>,<br><span class="hljs-string">"email"</span>: <span class="hljs-string">"[email protected]"</span>,<br>}<br><br>fmt.Printf(<span class="hljs-string">"m2: %v\n"</span>, m2)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs vim">m1: <span class="hljs-keyword">map</span>[age:<span class="hljs-number">20</span> emai<span class="hljs-variable">l:tom</span>@gmail.<span class="hljs-keyword">com</span> name:tom]<br>m2: <span class="hljs-keyword">map</span>[age:<span class="hljs-number">20</span> emai<span class="hljs-variable">l:kite</span>@gmail.<span class="hljs-keyword">com</span> name:kite]<br></code></pre></td></tr></table></figure><h2 id="访问map"><a href="#访问map" class="headerlink" title="访问map"></a>访问map</h2><p>可以通过下标key获得其值,例如:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>m1 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br>m1[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br>m1[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br>m1[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><br>name := m1[<span class="hljs-string">"name"</span>]<br>age := m1[<span class="hljs-string">"age"</span>]<br>email := m1[<span class="hljs-string">"email"</span>]<br>fmt.Printf(<span class="hljs-string">"name: %v\n"</span>, name)<br>fmt.Printf(<span class="hljs-string">"age: %v\n"</span>, age)<br>fmt.Printf(<span class="hljs-string">"email: %v\n"</span>, email)<br>}<br></code></pre></td></tr></table></figure><h2 id="判断某个键是否存在"><a href="#判断某个键是否存在" class="headerlink" title="判断某个键是否存在"></a>判断某个键是否存在</h2><p>go语言中有个判断map中键是否存在的特殊写法,格式如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">value, ok := <span class="hljs-keyword">map</span>[key]<br></code></pre></td></tr></table></figure><p>如果ok为<code>true</code>,存在;否则,不存在。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>m1 := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br>m1[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br>m1[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br>m1[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><br>v, ok := m1[<span class="hljs-string">"address"</span>]<br><span class="hljs-keyword">if</span> ok {<br>fmt.Println(<span class="hljs-string">"键存在"</span>)<br>fmt.Println(v)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"键不存在"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">键不存在<br></code></pre></td></tr></table></figure><h2 id="遍历map"><a href="#遍历map" class="headerlink" title="遍历map"></a>遍历map</h2><p>可以使用<code>for range</code>循环进行map遍历,得到key和value值。</p><h3 id="遍历key"><a href="#遍历key" class="headerlink" title="遍历key"></a>遍历key</h3><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs golang"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> m := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br> m[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br> m[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br> m[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><br> <span class="hljs-keyword">for</span> key := <span class="hljs-keyword">range</span> m{<br> fmt.Println(key)<br> }<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight delphi"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs delphi"><span class="hljs-keyword">name</span><br>age<br>email<br></code></pre></td></tr></table></figure><h3 id="遍历key和value"><a href="#遍历key和value" class="headerlink" title="遍历key和value"></a>遍历key和value</h3><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs golang"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> m := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br> m[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br> m[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br> m[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><br> <span class="hljs-keyword">for</span> key, value := <span class="hljs-keyword">range</span> m{<br> fmt.Println(key + <span class="hljs-string">":"</span> +value)<br> }<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs avrasm"><span class="hljs-symbol">name:</span>tom<br><span class="hljs-symbol">age:</span><span class="hljs-number">20</span><br><span class="hljs-symbol">email:</span>[email protected]<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-08-切片</title>
<link href="/2024/08/13/golang-08-silce/"/>
<url>/2024/08/13/golang-08-silce/</url>
<content type="html"><![CDATA[<h1 id="切片"><a href="#切片" class="headerlink" title="切片"></a>切片</h1><p>前面我们学习了数组,数组是固定长度,可以容纳相同数据类型的元素的集合。当长度固定时,使用还是带来一些限制,比如:我们申请的长度太大浪费内存,太小又不够用。</p><p>鉴于上述原因,我们有了go语言的切片,可以把切片理解为,可变长度的数组,其实它底层就是使用数组实现的,增加了<strong>自动扩容</strong>功能。切片(Slice)是一个拥有相同类型元素的可变长度的序列。</p><h2 id="切片的语法"><a href="#切片的语法" class="headerlink" title="切片的语法"></a>切片的语法</h2><p>声明一个切片和声明一个数组类似,只要不添加长度就可以了</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> identifier []<span class="hljs-keyword">type</span><br></code></pre></td></tr></table></figure><p>切片是引用类型,可以使用<code>make</code>函数来创建切片:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> slice1 []<span class="hljs-keyword">type</span> = <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">type</span>, <span class="hljs-built_in">len</span>)<br><br>也可以简写为<br><br>slice1 := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">type</span>, <span class="hljs-built_in">len</span>)<br></code></pre></td></tr></table></figure><p>也可以指定容量,其中capacity为可选参数。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-built_in">make</span>([]T, length, capacity)<br></code></pre></td></tr></table></figure><p>这里 len 是数组的长度并且也是切片的初始长度。</p><h2 id="切片实例"><a href="#切片实例" class="headerlink" title="切片实例"></a>切片实例</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> names []<span class="hljs-type">string</span><br><span class="hljs-keyword">var</span> numbers []<span class="hljs-type">int</span><br>fmt.Printf(<span class="hljs-string">"names: %v\n"</span>, names)<br>fmt.Printf(<span class="hljs-string">"numbers: %v\n"</span>, numbers)<br>fmt.Println(names == <span class="hljs-literal">nil</span>)<br>fmt.Println(numbers == <span class="hljs-literal">nil</span>)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">names:</span> []<br><span class="hljs-attr">numbers:</span> []<br><span class="hljs-literal">true</span><br><span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><h2 id="切片的长度和容量"><a href="#切片的长度和容量" class="headerlink" title="切片的长度和容量"></a>切片的长度和容量</h2><p>切片拥有自己的长度和容量,我们可以通过使用内置的<code>len()</code>函数求长度,使用内置的<code>cap()</code>函数求切片的容量。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> names = []<span class="hljs-type">string</span>{<span class="hljs-string">"tom"</span>, <span class="hljs-string">"kite"</span>}<br><span class="hljs-keyword">var</span> numbers = []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br><br>fmt.Printf(<span class="hljs-string">"len: %d cap: %d\n"</span>, <span class="hljs-built_in">len</span>(names), <span class="hljs-built_in">cap</span>(names))<br>fmt.Printf(<span class="hljs-string">"len: %d cap: %d\n"</span>, <span class="hljs-built_in">len</span>(numbers), <span class="hljs-built_in">cap</span>(numbers))<br><br><span class="hljs-keyword">var</span> s1 = <span class="hljs-built_in">make</span>([]<span class="hljs-type">string</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)<br>fmt.Printf(<span class="hljs-string">"len: %d cap: %d\n"</span>, <span class="hljs-built_in">len</span>(s1), <span class="hljs-built_in">cap</span>(s1))<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">len</span>: <span class="hljs-number">2</span> cap: <span class="hljs-number">2</span><br><span class="hljs-attribute">len</span>: <span class="hljs-number">3</span> cap: <span class="hljs-number">3</span><br><span class="hljs-attribute">len</span>: <span class="hljs-number">2</span> cap: <span class="hljs-number">3</span><br></code></pre></td></tr></table></figure><h2 id="切片的初始化"><a href="#切片的初始化" class="headerlink" title="切片的初始化"></a>切片的初始化</h2><p>切片的初始化方法很多,可以直接初始化,也可以使用数组初始化等。</p><h3 id="切片如何切分"><a href="#切片如何切分" class="headerlink" title="切片如何切分"></a>切片如何切分</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">// 切片</span><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test1</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> s1 = []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>}<br>s2 := s1[<span class="hljs-number">0</span>:<span class="hljs-number">3</span>] <span class="hljs-comment">// [)</span><br>fmt.Printf(<span class="hljs-string">"s2: %v\n"</span>, s2)<br>s3 := s1[<span class="hljs-number">3</span>:]<br>fmt.Printf(<span class="hljs-string">"s3: %v\n"</span>, s3)<br>s4 := s1[<span class="hljs-number">2</span>:<span class="hljs-number">5</span>]<br>fmt.Printf(<span class="hljs-string">"s4: %v\n"</span>, s4)<br>s5 := s1[:]<br>fmt.Printf(<span class="hljs-string">"s5: %v\n"</span>, s5)<br>}<br></code></pre></td></tr></table></figure><h3 id="直接初始化"><a href="#直接初始化" class="headerlink" title="直接初始化"></a>直接初始化</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br>fmt.Printf(<span class="hljs-string">"s: %v\n"</span>, s)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s</span>:<span class="hljs-meta"> [1 2 3]</span><br></code></pre></td></tr></table></figure><h3 id="使用数组初始化"><a href="#使用数组初始化" class="headerlink" title="使用数组初始化"></a>使用数组初始化</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>arr := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br>s1 := arr[:]<br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s1</span>:<span class="hljs-meta"> [1 2 3]</span><br></code></pre></td></tr></table></figure><h3 id="使用数组的部分元素初始化(切片表达式)"><a href="#使用数组的部分元素初始化(切片表达式)" class="headerlink" title="使用数组的部分元素初始化(切片表达式)"></a>使用数组的部分元素初始化(切片表达式)</h3><p>切片的底层就是一个<strong>数组</strong>,所以我们可以<strong>基于数组通过切片表达式得到切片</strong>。 切片表达式中的low和high表示一个索引范围(<strong>左包含,右不包含</strong>),得到的切片<strong>长度</strong>=high-low,容量等于得到的切片的底层数组的容量。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>arr := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>}<br>s1 := arr[<span class="hljs-number">2</span>:<span class="hljs-number">5</span>]<br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br>s2 := arr[<span class="hljs-number">2</span>:]<br>fmt.Printf(<span class="hljs-string">"s2: %v\n"</span>, s2)<br>s3 := arr[:<span class="hljs-number">3</span>]<br>fmt.Printf(<span class="hljs-string">"s3: %v\n"</span>, s3)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s1</span>:<span class="hljs-meta"> [3 4 5]</span><br><span class="hljs-attribute">s2</span>:<span class="hljs-meta"> [3 4 5 6]</span><br><span class="hljs-attribute">s3</span>:<span class="hljs-meta"> [1 2 3]</span><br></code></pre></td></tr></table></figure><h3 id="空-nil-切片"><a href="#空-nil-切片" class="headerlink" title="空(nil)切片"></a>空(nil)切片</h3><p>一个切片在未初始化之前默认为 nil,长度为 0,容量为0.</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> s1 []<span class="hljs-type">int</span><br>fmt.Println(s1 == <span class="hljs-literal">nil</span>)<br>fmt.Printf(<span class="hljs-string">"len: %d, cap: %d\n"</span>, <span class="hljs-built_in">len</span>(s1), <span class="hljs-built_in">cap</span>(s1))<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-literal">true</span><br><span class="hljs-built_in">len</span>: <span class="hljs-number">0</span>, <span class="hljs-built_in">cap</span>: <span class="hljs-number">0</span><br></code></pre></td></tr></table></figure><h2 id="切片的遍历"><a href="#切片的遍历" class="headerlink" title="切片的遍历"></a>切片的遍历</h2><p>切片的遍历和数组的遍历非常类似,可以使用for循环索引遍历,或者for range循环。</p><h3 id="for循环索引遍历"><a href="#for循环索引遍历" class="headerlink" title="for循环索引遍历"></a>for循环索引遍历</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s1 := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-built_in">len</span>(s1); i++ {<br>fmt.Printf(<span class="hljs-string">"s1[%d]: %v\n"</span>, i, s1[i])<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s1</span>[<span class="hljs-number">0</span>]: <span class="hljs-number">1</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">1</span>]: <span class="hljs-number">2</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">2</span>]: <span class="hljs-number">3</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">3</span>]: <span class="hljs-number">4</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">4</span>]: <span class="hljs-number">5</span><br></code></pre></td></tr></table></figure><h3 id="for-range循环"><a href="#for-range循环" class="headerlink" title="for range循环"></a>for range循环</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s1 := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br><span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> s1 {<br>fmt.Printf(<span class="hljs-string">"s1[%d]: %v\n"</span>, i, v)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s1</span>[<span class="hljs-number">0</span>]: <span class="hljs-number">1</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">1</span>]: <span class="hljs-number">2</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">2</span>]: <span class="hljs-number">3</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">3</span>]: <span class="hljs-number">4</span><br><span class="hljs-attribute">s1</span>[<span class="hljs-number">4</span>]: <span class="hljs-number">5</span><br></code></pre></td></tr></table></figure><h2 id="切片元素的添加和删除copy"><a href="#切片元素的添加和删除copy" class="headerlink" title="切片元素的添加和删除copy"></a>切片元素的添加和删除copy</h2><p>切片是一个动态数组,可以使用<code>append()</code>函数添加元素,go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。由于,切片是引用类型,通过赋值的方式,会修改原有内容,go提供了<code>copy()</code>函数来拷贝切片</p><p>db CRUD</p><h3 id="添加元素"><a href="#添加元素" class="headerlink" title="添加元素"></a>添加元素</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s1 := []<span class="hljs-type">int</span>{}<br>s1 = <span class="hljs-built_in">append</span>(s1, <span class="hljs-number">1</span>)<br>s1 = <span class="hljs-built_in">append</span>(s1, <span class="hljs-number">2</span>)<br>s1 = <span class="hljs-built_in">append</span>(s1, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>) <span class="hljs-comment">// 添加多个元素</span><br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br><br>s3 := []<span class="hljs-type">int</span>{<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br>s4 := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>}<br>s4 = <span class="hljs-built_in">append</span>(s4, s3...) <span class="hljs-comment">// 添加另外一个切片</span><br>fmt.Printf(<span class="hljs-string">"s4: %v\n"</span>, s4)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight tap"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs tap">s1: [1<span class="hljs-number"> 2 </span>3<span class="hljs-number"> 4 </span>5]<br>s4: [1<span class="hljs-number"> 2 </span>3<span class="hljs-number"> 4 </span>5]<br></code></pre></td></tr></table></figure><h3 id="删除元素"><a href="#删除元素" class="headerlink" title="删除元素"></a>删除元素</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s1 := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br><span class="hljs-comment">// 删除索引为2的元素</span><br>s1 = <span class="hljs-built_in">append</span>(s1[:<span class="hljs-number">2</span>], s1[<span class="hljs-number">3</span>:]...)<br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">s1</span>:<span class="hljs-meta"> [1 2 4 5]</span><br></code></pre></td></tr></table></figure><p>公式:要从切片a中删除索引为<code>index</code>的元素,操作方法是<code>a = append(a[:index], a[index+1:]...)</code></p><h3 id="拷贝切片"><a href="#拷贝切片" class="headerlink" title="拷贝切片"></a>拷贝切片</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s1 := []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br>s2 := s1<br>s1[<span class="hljs-number">0</span>] = <span class="hljs-number">100</span><br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br>fmt.Printf(<span class="hljs-string">"s2: %v\n"</span>, s2)<br>fmt.Println(<span class="hljs-string">"----------"</span>)<br><br>s3 := <span class="hljs-built_in">make</span>([]<span class="hljs-type">int</span>, <span class="hljs-number">3</span>)<br><br><span class="hljs-built_in">copy</span>(s3, s1)<br><br>s1[<span class="hljs-number">0</span>] = <span class="hljs-number">1</span><br><br>fmt.Printf(<span class="hljs-string">"s1: %v\n"</span>, s1)<br>fmt.Printf(<span class="hljs-string">"s3: %v\n"</span>, s3)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight ldif"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs ldif"><span class="hljs-attribute">s1</span>: [100 2 3]<br><span class="hljs-attribute">s2</span>: [100 2 3]<br><span class="hljs-literal">-</span>------------<br><span class="hljs-attribute">s1</span>: [1 2 3]<br><span class="hljs-attribute">s3</span>: [100 2 3]<br></code></pre></td></tr></table></figure><p>从运行结果,我们看到赋值的情况下,原来的变量被修改了,使用copy函数,原来的变量没有被修改。</p>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-07-数组</title>
<link href="/2024/08/13/golang-07-array/"/>
<url>/2024/08/13/golang-07-array/</url>
<content type="html"><![CDATA[<h1 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h1><p>数组是<strong>相同数据类型</strong>的一组数据的集合,数组一旦定义<strong>长度不能修改</strong>,数组可以通过<strong>下标(或者叫索引)</strong>来访问元素。</p><h2 id="数组的定义"><a href="#数组的定义" class="headerlink" title="数组的定义"></a>数组的定义</h2><p>数组定义的语法如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> variable_name [SIZE] variable_type<br></code></pre></td></tr></table></figure><p><code>variable_name</code>:数组名称</p><p><code>SIZE</code>:数组长度,必须是常量</p><p><code>variable_type</code>:数组保存元素的类型</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a [<span class="hljs-number">3</span>]<span class="hljs-type">int</span> <span class="hljs-comment">// 定义一个int类型的数组a,长度是3</span><br><span class="hljs-keyword">var</span> s [<span class="hljs-number">2</span>]<span class="hljs-type">string</span> <span class="hljs-comment">// 定义一个字符串类型的数组s,长度是2</span><br><br>fmt.Printf(<span class="hljs-string">"a: %T\n"</span>, a)<br>fmt.Printf(<span class="hljs-string">"s: %T\n"</span>, s)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-selector-tag">a</span>: <span class="hljs-selector-attr">[3]</span>int<br>s: <span class="hljs-selector-attr">[2]</span>string<br></code></pre></td></tr></table></figure><p>从上面运行结果,我们可以看出,数组和长度和元素类型共同组成了数组的类型。</p><h2 id="数组的初始化"><a href="#数组的初始化" class="headerlink" title="数组的初始化"></a>数组的初始化</h2><p>初始化,就是给数组的元素赋值,没有初始化的数组,默认元素值都是<strong>零值</strong>,布尔类型是<code>false</code>,字符串是空字符串。</p><h3 id="没有初始化的数组"><a href="#没有初始化的数组" class="headerlink" title="没有初始化的数组"></a>没有初始化的数组</h3><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a [<span class="hljs-number">3</span>]<span class="hljs-type">int</span> <span class="hljs-comment">// 定义一个int类型的数组a,长度是3</span><br><span class="hljs-keyword">var</span> s [<span class="hljs-number">2</span>]<span class="hljs-type">string</span> <span class="hljs-comment">// 定义一个字符串类型的数组s,长度是2</span><br><span class="hljs-keyword">var</span> b [<span class="hljs-number">2</span>]<span class="hljs-type">bool</span><br><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>fmt.Printf(<span class="hljs-string">"s: %v\n"</span>, s)<br>fmt.Printf(<span class="hljs-string">"b: %v\n"</span>, b)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-selector-tag">a</span>: <span class="hljs-selector-attr">[0 0 0]</span><br>s: <span class="hljs-selector-attr">[<span class="hljs-string">""</span> <span class="hljs-string">""</span>]</span><br><span class="hljs-selector-tag">b</span>: <span class="hljs-selector-attr">[false false]</span><br></code></pre></td></tr></table></figure><h3 id="使用初始化列表"><a href="#使用初始化列表" class="headerlink" title="使用初始化列表"></a>使用初始化列表</h3><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a = [<span class="hljs-number">3</span>]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br><span class="hljs-keyword">var</span> s = [<span class="hljs-number">2</span>]<span class="hljs-type">string</span>{<span class="hljs-string">"tom"</span>, <span class="hljs-string">"kite"</span>}<br><span class="hljs-keyword">var</span> b = [<span class="hljs-number">2</span>]<span class="hljs-type">bool</span>{<span class="hljs-literal">true</span>, <span class="hljs-literal">false</span>}<br><br>a1 := [<span class="hljs-number">2</span>]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>} <span class="hljs-comment">// 类型推断</span><br><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>fmt.Printf(<span class="hljs-string">"s: %v\n"</span>, s)<br>fmt.Printf(<span class="hljs-string">"b: %v\n"</span>, b)<br>fmt.Printf(<span class="hljs-string">"a1: %v\n"</span>, a1)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-selector-tag">a</span>: <span class="hljs-selector-attr">[1 2 3]</span><br>s: <span class="hljs-selector-attr">[tom kite]</span><br><span class="hljs-selector-tag">b</span>: <span class="hljs-selector-attr">[true false]</span><br>a1: <span class="hljs-selector-attr">[1 2]</span><br></code></pre></td></tr></table></figure><p>使用初始化列表,就是将值写在<strong>大括号</strong>里面。</p><h3 id="省略数组长度"><a href="#省略数组长度" class="headerlink" title="省略数组长度"></a>省略数组长度</h3><p>数组长度可以省略,使用<code>...</code>代替,更加初始化值得数量<strong>自动推断</strong>,例如:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a = [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}<br><span class="hljs-keyword">var</span> s = [...]<span class="hljs-type">string</span>{<span class="hljs-string">"tom"</span>, <span class="hljs-string">"kite"</span>}<br><span class="hljs-keyword">var</span> b = [...]<span class="hljs-type">bool</span>{<span class="hljs-literal">true</span>, <span class="hljs-literal">false</span>}<br><br>a1 := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>} <span class="hljs-comment">// 类型推断</span><br><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>fmt.Printf(<span class="hljs-string">"s: %v\n"</span>, s)<br>fmt.Printf(<span class="hljs-string">"b: %v\n"</span>, b)<br>fmt.Printf(<span class="hljs-string">"a1: %v\n"</span>, a1)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-selector-tag">a</span>: <span class="hljs-selector-attr">[1 2 3]</span><br>s: <span class="hljs-selector-attr">[tom kite]</span><br><span class="hljs-selector-tag">b</span>: <span class="hljs-selector-attr">[true false]</span><br>a1: <span class="hljs-selector-attr">[1 2]</span><br></code></pre></td></tr></table></figure><h3 id="指定索引值的方式来初始化"><a href="#指定索引值的方式来初始化" class="headerlink" title="指定索引值的方式来初始化"></a>指定索引值的方式来初始化</h3><p>可以通过指定所有的方式来初始化,未指定所有的默认未零值。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a = [...]<span class="hljs-type">int</span>{<span class="hljs-number">0</span>: <span class="hljs-number">1</span>, <span class="hljs-number">2</span>: <span class="hljs-number">2</span>}<br><span class="hljs-keyword">var</span> s = [...]<span class="hljs-type">string</span>{<span class="hljs-number">1</span>: <span class="hljs-string">"tom"</span>, <span class="hljs-number">2</span>: <span class="hljs-string">"kite"</span>}<br><span class="hljs-keyword">var</span> b = [...]<span class="hljs-type">bool</span>{<span class="hljs-number">2</span>: <span class="hljs-literal">true</span>, <span class="hljs-number">5</span>: <span class="hljs-literal">false</span>}<br><br>a1 := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>} <span class="hljs-comment">// 类型推断</span><br><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>fmt.Printf(<span class="hljs-string">"s: %v\n"</span>, s)<br>fmt.Printf(<span class="hljs-string">"b: %v\n"</span>, b)<br>fmt.Printf(<span class="hljs-string">"a1: %v\n"</span>, a1)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">a:</span> [<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">2</span>]<br><span class="hljs-attr">s:</span> [ <span class="hljs-string">tom</span> <span class="hljs-string">kite</span>]<br><span class="hljs-attr">b:</span> [<span class="hljs-literal">false</span> <span class="hljs-literal">false</span> <span class="hljs-literal">true</span> <span class="hljs-literal">false</span> <span class="hljs-literal">false</span> <span class="hljs-literal">false</span>]<br><span class="hljs-attr">a1:</span> [<span class="hljs-number">1</span> <span class="hljs-number">2</span>]<br></code></pre></td></tr></table></figure><h2 id="访问数组元素"><a href="#访问数组元素" class="headerlink" title="访问数组元素"></a>访问数组元素</h2><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a [<span class="hljs-number">2</span>]<span class="hljs-type">int</span><br>a[<span class="hljs-number">0</span>] = <span class="hljs-number">100</span><br>a[<span class="hljs-number">1</span>] = <span class="hljs-number">200</span><br><br>fmt.Printf(<span class="hljs-string">"a[0]: %v\n"</span>, a[<span class="hljs-number">0</span>])<br>fmt.Printf(<span class="hljs-string">"a[0]: %v\n"</span>, a[<span class="hljs-number">1</span>])<br><br><span class="hljs-comment">// 修改 a[0] a[1]</span><br>a[<span class="hljs-number">0</span>] = <span class="hljs-number">1</span><br>a[<span class="hljs-number">1</span>] = <span class="hljs-number">2</span><br><br>fmt.Println(<span class="hljs-string">"-----------"</span>)<br><br>fmt.Printf(<span class="hljs-string">"a[0]: %v\n"</span>, a[<span class="hljs-number">0</span>])<br>fmt.Printf(<span class="hljs-string">"a[0]: %v\n"</span>, a[<span class="hljs-number">1</span>])<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs less"><span class="hljs-selector-tag">a</span><span class="hljs-selector-attr">[0]</span>: <span class="hljs-number">100</span><br><span class="hljs-selector-tag">a</span><span class="hljs-selector-attr">[0]</span>: <span class="hljs-number">200</span><br><span class="hljs-selector-tag">-----------</span><br><span class="hljs-selector-tag">a</span><span class="hljs-selector-attr">[0]</span>: <span class="hljs-number">1</span><br><span class="hljs-selector-tag">a</span><span class="hljs-selector-attr">[0]</span>: <span class="hljs-number">2</span><br></code></pre></td></tr></table></figure><h2 id="根据数组长度遍历数组"><a href="#根据数组长度遍历数组" class="headerlink" title="根据数组长度遍历数组"></a>根据数组长度遍历数组</h2><p>可以根据数组长度,通过<code>for</code>循环的方式来遍历数组,数组的长度可以使用<code>len</code>函数获得。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>}<br><br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-built_in">len</span>(a); i++ {<br>fmt.Printf(<span class="hljs-string">"a[%d]: %v\n"</span>, i, a[i])<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">a</span>[<span class="hljs-number">0</span>]: <span class="hljs-number">1</span><br><span class="hljs-attribute">a</span>[<span class="hljs-number">1</span>]: <span class="hljs-number">2</span><br><span class="hljs-attribute">a</span>[<span class="hljs-number">2</span>]: <span class="hljs-number">3</span><br><span class="hljs-attribute">a</span>[<span class="hljs-number">3</span>]: <span class="hljs-number">4</span><br><span class="hljs-attribute">a</span>[<span class="hljs-number">4</span>]: <span class="hljs-number">5</span><br><span class="hljs-attribute">a</span>[<span class="hljs-number">5</span>]: <span class="hljs-number">6</span><br></code></pre></td></tr></table></figure><h2 id="使用for-range数组"><a href="#使用for-range数组" class="headerlink" title="使用for range数组"></a>使用<code>for range</code>数组</h2><p>还可以使用<code>for range</code>循环来遍历数组,range返回数组下标和对应的值</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := [...]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>}<br><br><span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> a {<br>fmt.Printf(<span class="hljs-string">"a[%d]: %v\n"</span>, i, v)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go">a[<span class="hljs-number">0</span>]: <span class="hljs-number">1</span><br>a[<span class="hljs-number">1</span>]: <span class="hljs-number">2</span><br>a[<span class="hljs-number">2</span>]: <span class="hljs-number">3</span><br>a[<span class="hljs-number">3</span>]: <span class="hljs-number">4</span><br>a[<span class="hljs-number">4</span>]: <span class="hljs-number">5</span><br>a[<span class="hljs-number">5</span>]: <span class="hljs-number">6</span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-06-流程控制</title>
<link href="/2024/08/13/golang-06-ifelse/"/>
<url>/2024/08/13/golang-06-ifelse/</url>
<content type="html"><![CDATA[<h1 id="流程控制"><a href="#流程控制" class="headerlink" title="流程控制"></a>流程控制</h1><h2 id="条件语句"><a href="#条件语句" class="headerlink" title="条件语句"></a>条件语句</h2><p><strong>条件语句</strong>是用来判断给定的条件是否满足(表达式值是否为<code>true</code>或者<code>false</code>),并根据判断的结果(真或假)决定执行的语句,go语言中的条件语句也是这样的。</p><h2 id="条件语句包含如下"><a href="#条件语句包含如下" class="headerlink" title="条件语句包含如下"></a>条件语句包含如下</h2><ol><li><strong>if 语句</strong>:<code>if</code> 语句 由一个布尔表达式后紧跟一个或多个语句组成。</li><li><strong>if…else 语句</strong>: <code>if</code> 语句 后可以使用可选的 <code>else</code> 语句, <code>else</code> 语句中的表达式在布尔表达式为 <code>false</code> 时执行。</li><li><strong>if 嵌套语句</strong>: 你可以在 <code>if</code> 或 <code>else if</code> 语句中嵌入一个或多个 <code>if</code> 或 <code>else if</code> 语句。</li><li><strong>switch 语句</strong>: <code>switch</code> 语句用于基于不同条件执行不同动作。</li><li><strong>select 语句</strong>: <code>select</code> 语句类似于 <code>switch</code> 语句,但是<code>select</code>会随机执行一个可运行的<code>case</code>。如果没有<code>case</code>可运行,它将阻塞,直到有<code>case</code>可运行。</li></ol><h2 id="循环语句"><a href="#循环语句" class="headerlink" title="循环语句"></a>循环语句</h2><p>go语言中的循环只有for循环,去除了<code>while</code>、<code>do while</code>循环,使用起来更加简洁。</p><ol><li>for循环。</li><li>for range循环。</li></ol><h2 id="流程控制关键字"><a href="#流程控制关键字" class="headerlink" title="流程控制关键字"></a>流程控制关键字</h2><ol><li>break</li><li>continue</li><li>goto</li></ol><p><strong>go语言</strong>中的<strong>if语句</strong>和其他语言中的类似,都是根据给定的条件表达式运算结果来,判断执行流程。</p><h1 id=""><a href="#" class="headerlink" title=""></a></h1><h1 id="if语句语法"><a href="#if语句语法" class="headerlink" title="if语句语法"></a>if语句语法</h1><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">if</span> 布尔表达式 {<br> <span class="hljs-comment">/* 在布尔表达式为 true 时执行 */</span><br>}<br></code></pre></td></tr></table></figure><blockquote><p>注意:在go语言中 布尔表达式不用使用括号。</p></blockquote><h2 id="if语句实例演示"><a href="#if语句实例演示" class="headerlink" title="if语句实例演示"></a>if语句实例演示</h2><p><strong>根据布尔值flag判断</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test1</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> flag = <span class="hljs-literal">true</span><br><span class="hljs-keyword">if</span> flag {<br>fmt.Println(<span class="hljs-string">"flag is true"</span>)<br>}<br>fmt.Printf(<span class="hljs-string">"程序运行结束"</span>)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>test1()<br>}<br></code></pre></td></tr></table></figure><p>程序运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go">flag is <span class="hljs-literal">true</span><br>程序运行结束<br></code></pre></td></tr></table></figure><p><strong>根据年龄判断是否成年</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test2</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> age = <span class="hljs-number">20</span><br><span class="hljs-keyword">if</span> age > <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"你是成年人"</span>)<br>}<br>fmt.Printf(<span class="hljs-string">"程序运行结束"</span>)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>test2()<br>}<br></code></pre></td></tr></table></figure><p>程序运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go">你是成年人<br>程序运行结束<br></code></pre></td></tr></table></figure><blockquote><p><strong>初始变量可以声明在布尔表达式里面,注意它的作用域</strong></p></blockquote><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test3</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">if</span> age := <span class="hljs-number">20</span>; age > <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"你是成年人"</span>)<br>}<br>fmt.Printf(<span class="hljs-string">"程序运行结束"</span>)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-comment">// test1()</span><br><span class="hljs-comment">// test2()</span><br>test3()<br>}<br></code></pre></td></tr></table></figure><p>程序运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs">你是成年人<br>程序运行结束<br></code></pre></td></tr></table></figure><blockquote><p><strong>注意:不能使用0或非0表示真假</strong></p></blockquote><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">test4</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> i = <span class="hljs-number">1</span><br><span class="hljs-keyword">if</span> i { <span class="hljs-comment">// 编译失败</span><br>fmt.Println(<span class="hljs-string">"here"</span>)<br>}<br>fmt.Printf(<span class="hljs-string">"程序运行结束"</span>)<br>}<br></code></pre></td></tr></table></figure><p><strong>go语言if语句使用提示:</strong></p><ol><li>不需使用括号将<strong>条件包含起来</strong></li><li>大括号<code>{}</code>必须存在,即使只有一行语句</li><li>左括号必须在<code>if</code>或<code>else</code>的同一行</li><li>在<code>if</code>之后,条件语句之前,可以添加变量初始化语句,使用<code>;</code>进行分隔</li></ol><h2 id="if-else语句"><a href="#if-else语句" class="headerlink" title="if else语句"></a>if else语句</h2><p>go语言中的if else语句可以根据给定条件<strong>二选一</strong>。</p><h3 id="if-else语句语法"><a href="#if-else语句语法" class="headerlink" title="if else语句语法"></a>if else语句语法</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">if</span> 布尔表达式 {<br> <span class="hljs-comment">/* 在布尔表达式为 true 时执行 */</span><br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">/* 在布尔表达式为 false 时执行 */</span><br>}<br></code></pre></td></tr></table></figure><h3 id="if-else语句实例"><a href="#if-else语句实例" class="headerlink" title="if else语句实例"></a>if else语句实例</h3><h4 id="比较两个数的大小"><a href="#比较两个数的大小" class="headerlink" title="比较两个数的大小"></a><strong>比较两个数的大小</strong></h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f1</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">1</span><br>b := <span class="hljs-number">2</span><br><span class="hljs-keyword">if</span> a > b {<br>fmt.Printf(<span class="hljs-string">"\"a>b\": %v\n"</span>, <span class="hljs-string">"a>b"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Printf(<span class="hljs-string">"\"a<=b\": %v\n"</span>, <span class="hljs-string">"a<b"</span>)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f1()<br>}<br></code></pre></td></tr></table></figure><p><strong>判断一个数是奇数还是偶数</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f2</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> s <span class="hljs-type">int</span><br>fmt.Println(<span class="hljs-string">"输入一个数字:"</span>)<br>fmt.Scan(&s)<br><br><span class="hljs-keyword">if</span> s%<span class="hljs-number">2</span> == <span class="hljs-number">0</span> {<br>fmt.Print(<span class="hljs-string">"s 是偶数\n"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Print(<span class="hljs-string">"s 不是偶数\n"</span>)<br>}<br>fmt.Print(<span class="hljs-string">"s 的值是:"</span>, s)<br>}<br></code></pre></td></tr></table></figure><p><strong>判断一个人是否成年</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f3</span><span class="hljs-params">()</span></span> {<br>age := <span class="hljs-number">20</span><br><span class="hljs-keyword">if</span> age >= <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"你是成年人"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"你还未成年"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p><strong>特殊写法,在if前面添加执行语句</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f4</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">if</span> age := <span class="hljs-number">20</span>; age >= <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"你是成年人"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"你还未成年"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p><strong>go语言if语句使用提示:</strong></p><ol><li>不需使用括号将条件包含起来</li><li>大括号<code>{}</code>必须存在,即使只有<strong>一行语句</strong></li><li><strong>左括号</strong>必须在<code>if</code>或<code>else</code>的同一行</li><li>在<code>if</code>之后,条件语句之前,可以添加变量<strong>初始化语句</strong>,使用<code>;</code>进行分隔</li></ol><h2 id="if-else-if语句"><a href="#if-else-if语句" class="headerlink" title="if else if语句"></a>if else if语句</h2><p>go语言if语句可以进行多重嵌套使用,进行多重判断。</p><h3 id="if-else-if语法"><a href="#if-else-if语法" class="headerlink" title="if else if语法"></a>if else if语法</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">if</span> 布尔表达式<span class="hljs-number">1</span> {<br> <span class="hljs-comment">// do something</span><br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> 布尔表达式<span class="hljs-number">2</span> {<br> <span class="hljs-comment">// do something else</span><br>}<span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// catch-all or default</span><br>}<br></code></pre></td></tr></table></figure><h3 id="if-else-if语法实例"><a href="#if-else-if语法实例" class="headerlink" title="if else if语法实例"></a>if else if语法实例</h3><h4 id="根据分数判断等级"><a href="#根据分数判断等级" class="headerlink" title="根据分数判断等级"></a><strong>根据分数判断等级</strong></h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f5</span><span class="hljs-params">()</span></span> {<br>score := <span class="hljs-number">80</span><br><span class="hljs-keyword">if</span> score >= <span class="hljs-number">60</span> && score <= <span class="hljs-number">70</span> {<br>fmt.Println(<span class="hljs-string">"C"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> score > <span class="hljs-number">70</span> && score <= <span class="hljs-number">90</span> {<br>fmt.Println(<span class="hljs-string">"B"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"A"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>程序运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">B<br></code></pre></td></tr></table></figure><p><strong>同样也可以写成这样</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f5</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">if</span> score := <span class="hljs-number">80</span>; score >= <span class="hljs-number">60</span> && score <= <span class="hljs-number">70</span> {<br>fmt.Println(<span class="hljs-string">"C"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> score > <span class="hljs-number">70</span> && score <= <span class="hljs-number">90</span> {<br>fmt.Println(<span class="hljs-string">"B"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"A"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p><strong>输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f6</span><span class="hljs-params">()</span></span> {<br><span class="hljs-comment">// Monday Tuesday Wednesday Thursday Friday Saturday Sunday</span><br><span class="hljs-keyword">var</span> c <span class="hljs-type">string</span><br>fmt.Println(<span class="hljs-string">"输入一个字符:"</span>)<br>fmt.Scan(&c)<br><br><span class="hljs-keyword">if</span> c == <span class="hljs-string">"S"</span> {<br>fmt.Println(<span class="hljs-string">"输入第二个字符:"</span>)<br>fmt.Scan(&c)<br><span class="hljs-keyword">if</span> c == <span class="hljs-string">"a"</span> {<br>fmt.Println(<span class="hljs-string">"Saturday"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"u"</span> {<br>fmt.Println(<span class="hljs-string">"Sunday"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"输入错误"</span>)<br>}<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"F"</span> {<br>fmt.Println(<span class="hljs-string">"Friday"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"M"</span> {<br>fmt.Println(<span class="hljs-string">"Monday"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"T"</span> {<br>fmt.Println(<span class="hljs-string">"输入第二个字符:"</span>)<br>fmt.Scan(&c)<br><span class="hljs-keyword">if</span> c == <span class="hljs-string">"u"</span> {<br>fmt.Println(<span class="hljs-string">"Tuesday"</span>)<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"h"</span> {<br>fmt.Println(<span class="hljs-string">"Thursday"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"输入错误"</span>)<br>}<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> c == <span class="hljs-string">"W"</span> {<br>fmt.Println(<span class="hljs-string">"Wednesday"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"输入错误"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><h2 id="嵌套if语句"><a href="#嵌套if语句" class="headerlink" title="嵌套if语句"></a>嵌套if语句</h2><p>go语言if语句可以嵌套多级进行判断。</p><h3 id="if嵌套语法"><a href="#if嵌套语法" class="headerlink" title="if嵌套语法"></a>if嵌套语法</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">if</span> 布尔表达式 <span class="hljs-number">1</span> {<br> <span class="hljs-comment">/* 在布尔表达式 1 为 true 时执行 */</span><br> <span class="hljs-keyword">if</span> 布尔表达式 <span class="hljs-number">2</span> {<br> <span class="hljs-comment">/* 在布尔表达式 2 为 true 时执行 */</span><br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="if嵌套实例"><a href="#if嵌套实例" class="headerlink" title="if嵌套实例"></a>if嵌套实例</h3><h4 id="判断三个数的大小"><a href="#判断三个数的大小" class="headerlink" title="判断三个数的大小"></a><strong>判断三个数的大小</strong></h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-comment">// a>b a>c a</span><br><span class="hljs-comment">// b>a b>c b else c</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f1</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">100</span><br>b := <span class="hljs-number">200</span><br>c := <span class="hljs-number">3</span><br><span class="hljs-keyword">if</span> a > b {<br><span class="hljs-keyword">if</span> a > c {<br>fmt.Println(<span class="hljs-string">"a最大"</span>)<br>}<br>} <span class="hljs-keyword">else</span> {<br><span class="hljs-keyword">if</span> b > c {<br>fmt.Println(<span class="hljs-string">"b最大"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"c最大"</span>)<br>}<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f1()<br>}<br></code></pre></td></tr></table></figure><p><strong>判断男生还是女生,还有是否成年</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f2</span><span class="hljs-params">()</span></span> {<br><span class="hljs-comment">// 判断男女生及年龄</span><br>gender := <span class="hljs-string">"女生"</span><br>age := <span class="hljs-number">16</span><br><span class="hljs-keyword">if</span> gender == <span class="hljs-string">"男生"</span> {<br>fmt.Println(<span class="hljs-string">"男生"</span>)<br><span class="hljs-keyword">if</span> age > <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"成年"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"未成年"</span>)<br>}<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"女生"</span>)<br><span class="hljs-keyword">if</span> age > <span class="hljs-number">18</span> {<br>fmt.Println(<span class="hljs-string">"成年"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"未成年"</span>)<br>}<br>}<br>}<br></code></pre></td></tr></table></figure><h1 id="-1"><a href="#-1" class="headerlink" title=""></a></h1><h1 id="switch语句"><a href="#switch语句" class="headerlink" title="switch语句"></a>switch语句</h1><p>go语言中的<code>switch</code>语句,可以非常容易的判断多个值的情况。</p><h2 id="switch语句的语法"><a href="#switch语句的语法" class="headerlink" title="switch语句的语法"></a>switch语句的语法</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">switch</span> var1 {<br> <span class="hljs-keyword">case</span> val1:<br> ...<br> <span class="hljs-keyword">case</span> val2:<br> ...<br> <span class="hljs-keyword">default</span>:<br> ...<br>}<br></code></pre></td></tr></table></figure><h2 id="switch语句实例"><a href="#switch语句实例" class="headerlink" title="switch语句实例"></a><code>switch</code>语句实例</h2><p><strong>判断成绩</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>grade := <span class="hljs-string">"A"</span><br><span class="hljs-keyword">switch</span> grade {<br><span class="hljs-keyword">case</span> <span class="hljs-string">"A"</span>:<br>fmt.Println(<span class="hljs-string">"优秀"</span>)<br><span class="hljs-keyword">case</span> <span class="hljs-string">"B"</span>:<br>fmt.Println(<span class="hljs-string">"良好"</span>)<br><span class="hljs-keyword">default</span>:<br>fmt.Println(<span class="hljs-string">"一般"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">优秀<br></code></pre></td></tr></table></figure><p><strong>多条件匹配</strong></p><p>go语言<code>switch</code>语句,可以同时匹配多个条件,中间用逗号分隔,有其中一个匹配成功即可。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>day := <span class="hljs-number">3</span><br><span class="hljs-keyword">switch</span> day {<br><span class="hljs-keyword">case</span> <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>:<br>fmt.Println(<span class="hljs-string">"工作日"</span>)<br><span class="hljs-keyword">case</span> <span class="hljs-number">6</span>, <span class="hljs-number">7</span>:<br>fmt.Println(<span class="hljs-string">"休息日"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">工作日<br></code></pre></td></tr></table></figure><p><strong>case可以是条件表达式</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>score := <span class="hljs-number">90</span><br><span class="hljs-keyword">switch</span> {<br><span class="hljs-keyword">case</span> score >= <span class="hljs-number">90</span>:<br>fmt.Println(<span class="hljs-string">"享受假期"</span>)<br><span class="hljs-keyword">case</span> score < <span class="hljs-number">90</span> && score >= <span class="hljs-number">80</span>:<br>fmt.Println(<span class="hljs-string">"好好学习吧!"</span>)<br><span class="hljs-keyword">default</span>:<br>fmt.Println(<span class="hljs-string">"玩命学习!"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">享受假期<br></code></pre></td></tr></table></figure><p><strong><code>fallthrough</code>可以执行满足条件的下一个<code>case</code></strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f3</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">100</span><br><span class="hljs-keyword">switch</span> a {<br><span class="hljs-keyword">case</span> <span class="hljs-number">100</span>:<br>fmt.Println(<span class="hljs-string">"100"</span>)<br><span class="hljs-keyword">fallthrough</span><br><span class="hljs-keyword">case</span> <span class="hljs-number">200</span>:<br>fmt.Println(<span class="hljs-string">"200"</span>)<br><span class="hljs-keyword">case</span> <span class="hljs-number">300</span>:<br>fmt.Println(<span class="hljs-string">"300"</span>)<br><span class="hljs-keyword">default</span>:<br>fmt.Println(<span class="hljs-string">"other"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-number">100</span><br><span class="hljs-number">200</span><br></code></pre></td></tr></table></figure><h2 id="switch语句的注意事项"><a href="#switch语句的注意事项" class="headerlink" title="switch语句的注意事项"></a><code>switch</code>语句的注意事项</h2><ol><li>支持多条件匹配</li><li>不同的 <code>case</code> 之间不使用 <code>break</code> 分隔,默认只会执行一个 <code>case</code>。</li><li>如果想要执行多个 <code>case</code>,需要使用 <code>fallthrough</code> 关键字,也可用 <code>break</code> 终止。</li><li>分支还可以使用<strong>表达式</strong>,例如:<code>a>10</code>.</li></ol><h1 id="-2"><a href="#-2" class="headerlink" title=""></a></h1><h1 id="for循环语句"><a href="#for循环语句" class="headerlink" title="for循环语句"></a>for循环语句</h1><p>go语言中的<code>for</code>循环,只有<code>for</code>关键字,去除了像其他语言中的<code>while</code>和<code>do while</code>.</p><h2 id="for循环语法"><a href="#for循环语法" class="headerlink" title="for循环语法"></a>for循环语法</h2><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs abnf">for 初始语句<span class="hljs-comment">;条件表达式;结束语句{</span><br> 循环体语句<br>}<br></code></pre></td></tr></table></figure><blockquote><p>注意:for表达式不用加括号</p></blockquote><h2 id="for循环实例"><a href="#for循环实例" class="headerlink" title="for循环实例"></a>for循环实例</h2><p><strong>循环输出1到10</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i <= <span class="hljs-number">10</span>; i++ {<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go">i: <span class="hljs-number">1</span><br>i: <span class="hljs-number">2</span><br>i: <span class="hljs-number">3</span><br>i: <span class="hljs-number">4</span><br>i: <span class="hljs-number">5</span><br>i: <span class="hljs-number">6</span><br>i: <span class="hljs-number">7</span><br>i: <span class="hljs-number">8</span><br>i: <span class="hljs-number">9</span><br>i: <span class="hljs-number">10</span><br></code></pre></td></tr></table></figure><p><strong>初始条件,可以写到外面</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>i := <span class="hljs-number">1</span><br><span class="hljs-keyword">for</span> ; i <= <span class="hljs-number">10</span>; i++ {<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">i</span>: <span class="hljs-number">1</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">2</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">3</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">4</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">5</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">6</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">7</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">8</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">9</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">10</span><br></code></pre></td></tr></table></figure><p><strong>初始条件和结束条件都可以省略</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>i := <span class="hljs-number">1</span> <span class="hljs-comment">// 初始条件</span><br><span class="hljs-keyword">for</span> i <= <span class="hljs-number">10</span> {<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>i++ <span class="hljs-comment">// 结束条件</span><br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">i</span>: <span class="hljs-number">1</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">2</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">3</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">4</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">5</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">6</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">7</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">8</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">9</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">10</span><br></code></pre></td></tr></table></figure><p>这种情况类似其他语言中的<code>while</code>循环</p><p><strong>永真循环</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> {<br>fmt.Println(<span class="hljs-string">"我一直在执行~"</span>)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs lasso">我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br>我一直在执行~<br><span class="hljs-params">...</span><span class="hljs-params">...</span><br></code></pre></td></tr></table></figure><p>for循环可以通过<code>break</code>、<code>goto</code>、<code>return</code>、<code>panic</code>语句强制退出循环。</p><h2 id="for-range循环"><a href="#for-range循环" class="headerlink" title="for range循环"></a>for range循环</h2><p>Go语言中可以使用<code>for range</code>遍历数组、切片、字符串、map 及通道(channel)。 通过<code>for range</code>遍历的返回值有以下规律:</p><ol><li>数组、切片、字符串返回<strong>索引和值</strong>。</li><li>map返回键和值。</li><li>通道(channel)只返回通道内的值。</li></ol><h2 id="for-range实例"><a href="#for-range实例" class="headerlink" title="for range实例"></a>for range实例</h2><p><strong>循环数组</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a = [<span class="hljs-number">5</span>]<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br><span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> a {<br>fmt.Printf(<span class="hljs-string">"i: %d, v: %v\n"</span>, i, v)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go">i: <span class="hljs-number">0</span>, v: <span class="hljs-number">1</span><br>i: <span class="hljs-number">1</span>, v: <span class="hljs-number">2</span><br>i: <span class="hljs-number">2</span>, v: <span class="hljs-number">3</span><br>i: <span class="hljs-number">3</span>, v: <span class="hljs-number">4</span><br>i: <span class="hljs-number">4</span>, v: <span class="hljs-number">5</span><br></code></pre></td></tr></table></figure><p><strong>循环字符串</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> s = <span class="hljs-string">"多课网,go教程"</span><br><span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> s {<br>fmt.Printf(<span class="hljs-string">"i: %d, v: %c\n"</span>, i, v)<br>}<br><span class="hljs-comment">// %c 按照字符输出</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go">i: <span class="hljs-number">0</span>, v: 多<br>i: <span class="hljs-number">3</span>, v: 课<br>i: <span class="hljs-number">6</span>, v: 网<br>i: <span class="hljs-number">9</span>, v: ,<br>i: <span class="hljs-number">12</span>, v: g<br>i: <span class="hljs-number">13</span>, v: o<br>i: <span class="hljs-number">14</span>, v: 教<br>i: <span class="hljs-number">17</span>, v: 程<br></code></pre></td></tr></table></figure><p><strong>循环切片</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> s = []<span class="hljs-type">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}<br><span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> s {<br>fmt.Printf(<span class="hljs-string">"i, %d, v: %v\n"</span>, i, v)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p><strong>循环map</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>m := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>)<br>m[<span class="hljs-string">"name"</span>] = <span class="hljs-string">"tom"</span><br>m[<span class="hljs-string">"age"</span>] = <span class="hljs-string">"20"</span><br>m[<span class="hljs-string">"email"</span>] = <span class="hljs-string">"[email protected]"</span><br><span class="hljs-keyword">for</span> k, v := <span class="hljs-keyword">range</span> m {<br>fmt.Printf(<span class="hljs-string">"k: %v, v: %v\n"</span>, k, v)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs go">k: email, v: [email protected]<br>k: name, v: tom<br>k: age, v: <span class="hljs-number">20</span><br></code></pre></td></tr></table></figure><h1 id="-3"><a href="#-3" class="headerlink" title=""></a></h1><h1 id="流程控制关键字-1"><a href="#流程控制关键字-1" class="headerlink" title="流程控制关键字"></a>流程控制关键字</h1><h2 id="break"><a href="#break" class="headerlink" title="break"></a>break</h2><p><code>break</code>语句可以结束<code>for</code>、<code>switch</code>和<code>select</code>的代码块。</p><h3 id="break注意事项"><a href="#break注意事项" class="headerlink" title="break注意事项"></a>break注意事项</h3><ol><li>单独在<code>select</code>中使用<code>break</code>和不使用<code>break</code>没有啥区别。</li><li>单独在表达式<code>switch</code>语句,并且没有<code>fallthough</code>,使用<code>break</code>和不使用<code>break</code>没有啥区别。</li><li>单独在表达式<code>switch</code>语句,并且有<code>fallthough</code>,使用<code>break</code>能够终止<code>fallthough</code>后面的<code>case</code>语句的执行。</li><li>带标签的<code>break</code>,可以跳出多层<code>select/ switch</code>作用域。让<code>break</code>更加灵活,写法更加简单灵活,不需要使用控制变量一层一层跳出循环,没有带<code>break</code>的只能跳出当前语句块。</li></ol><h3 id="break关键字实例"><a href="#break关键字实例" class="headerlink" title="break关键字实例"></a>break关键字实例</h3><p><strong>跳出for循环</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++ {<br><span class="hljs-keyword">if</span> i == <span class="hljs-number">5</span> {<br><span class="hljs-keyword">break</span> <span class="hljs-comment">// 退出循环</span><br>}<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>}<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go">i: <span class="hljs-number">0</span><br>i: <span class="hljs-number">1</span><br>i: <span class="hljs-number">2</span><br>i: <span class="hljs-number">3</span><br>i: <span class="hljs-number">4</span><br></code></pre></td></tr></table></figure><p><strong>跳出switch</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>i := <span class="hljs-number">2</span><br><span class="hljs-keyword">switch</span> i {<br><span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:<br>fmt.Println(<span class="hljs-string">"等于1"</span>)<br><span class="hljs-keyword">break</span><br><span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:<br>fmt.Println(<span class="hljs-string">"等于2"</span>)<br><span class="hljs-keyword">break</span><br><span class="hljs-keyword">fallthrough</span><br><span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:<br>fmt.Println(<span class="hljs-string">"等于3"</span>)<br><span class="hljs-keyword">break</span><br><span class="hljs-keyword">default</span>:<br>fmt.Println(<span class="hljs-string">"不关心"</span>)<br><span class="hljs-keyword">break</span><br>}<br>}<br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">等于2<br></code></pre></td></tr></table></figure><p>注释掉<code>fallthrough</code>上面的<code>break</code>,运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go">等于<span class="hljs-number">2</span><br>等于<span class="hljs-number">3</span><br></code></pre></td></tr></table></figure><p><strong>跳转到标签处</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>MY_LABEL:<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++ {<br><span class="hljs-keyword">if</span> i == <span class="hljs-number">5</span> {<br><span class="hljs-keyword">break</span> MY_LABEL<br>}<br>fmt.Printf(<span class="hljs-string">"%v\n"</span>, i)<br>}<br>fmt.Println(<span class="hljs-string">"end..."</span>)<br>}<br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight erlang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs erlang"><span class="hljs-number">0</span><br><span class="hljs-number">1</span><br><span class="hljs-number">2</span><br><span class="hljs-number">3</span><br><span class="hljs-number">4</span><br><span class="hljs-keyword">end</span>...<br></code></pre></td></tr></table></figure><h2 id="continue"><a href="#continue" class="headerlink" title="continue"></a>continue</h2><p><code>continue</code>只能用在循环中,在go中只能用在<code>for</code>循环中,它可以终止本次循环,进行下一次循环。</p><p>在 <code>continue</code>语句后添加标签时,表示开始标签对应的循环。</p><h3 id="continue实例"><a href="#continue实例" class="headerlink" title="continue实例"></a><code>continue</code>实例</h3><p><strong>输出1到10之间的偶数</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++ {<br><span class="hljs-keyword">if</span> i%<span class="hljs-number">2</span> == <span class="hljs-number">0</span> {<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>}<br>}<br>}<br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">i</span>: <span class="hljs-number">0</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">2</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">4</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">6</span><br><span class="hljs-attribute">i</span>: <span class="hljs-number">8</span><br></code></pre></td></tr></table></figure><p><strong>跳转到label</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-comment">// MY_LABEL:</span><br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++ {<br>MY_LABEL:<br><span class="hljs-keyword">for</span> j := <span class="hljs-number">0</span>; j < <span class="hljs-number">5</span>; j++ {<br><span class="hljs-keyword">if</span> i == <span class="hljs-number">2</span> && j == <span class="hljs-number">2</span> {<br><span class="hljs-keyword">continue</span> MY_LABEL<br>}<br>fmt.Printf(<span class="hljs-string">"i=%d,j=%d\n"</span>, i, j)<br>}<br>}<br>}<br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs go">i=<span class="hljs-number">0</span>,j=<span class="hljs-number">0</span><br>i=<span class="hljs-number">0</span>,j=<span class="hljs-number">1</span><br>i=<span class="hljs-number">0</span>,j=<span class="hljs-number">2</span><br>i=<span class="hljs-number">0</span>,j=<span class="hljs-number">3</span><br>i=<span class="hljs-number">0</span>,j=<span class="hljs-number">4</span><br>i=<span class="hljs-number">1</span>,j=<span class="hljs-number">0</span><br>i=<span class="hljs-number">1</span>,j=<span class="hljs-number">1</span><br>i=<span class="hljs-number">1</span>,j=<span class="hljs-number">2</span><br>i=<span class="hljs-number">1</span>,j=<span class="hljs-number">3</span><br>i=<span class="hljs-number">1</span>,j=<span class="hljs-number">4</span><br>i=<span class="hljs-number">2</span>,j=<span class="hljs-number">0</span><br>i=<span class="hljs-number">2</span>,j=<span class="hljs-number">1</span><br>i=<span class="hljs-number">2</span>,j=<span class="hljs-number">3</span><br>i=<span class="hljs-number">2</span>,j=<span class="hljs-number">4</span><br>i=<span class="hljs-number">3</span>,j=<span class="hljs-number">0</span><br>i=<span class="hljs-number">3</span>,j=<span class="hljs-number">1</span><br>i=<span class="hljs-number">3</span>,j=<span class="hljs-number">2</span><br>i=<span class="hljs-number">3</span>,j=<span class="hljs-number">3</span><br>i=<span class="hljs-number">3</span>,j=<span class="hljs-number">4</span><br>i=<span class="hljs-number">4</span>,j=<span class="hljs-number">0</span><br>i=<span class="hljs-number">4</span>,j=<span class="hljs-number">1</span><br>i=<span class="hljs-number">4</span>,j=<span class="hljs-number">2</span><br>i=<span class="hljs-number">4</span>,j=<span class="hljs-number">3</span><br>i=<span class="hljs-number">4</span>,j=<span class="hljs-number">4</span><br></code></pre></td></tr></table></figure><h2 id="goto"><a href="#goto" class="headerlink" title="goto"></a>goto</h2><p><code>goto</code>语句通过标签进行代码间的<strong>无条件跳转</strong>。<code>goto</code>语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go语言中使用<code>goto</code>语句能简化一些代码的实现过程。 例如双层嵌套的for循环要退出时:</p><h3 id="goto实例"><a href="#goto实例" class="headerlink" title="goto实例"></a>goto实例</h3><p><strong>跳转到指定标签</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">0</span><br><span class="hljs-keyword">if</span> a == <span class="hljs-number">1</span> {<br><span class="hljs-keyword">goto</span> LABEL1<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"other"</span>)<br>}<br><br>LABEL1:<br>fmt.Printf(<span class="hljs-string">"next..."</span>)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs gams"><span class="hljs-function"><span class="hljs-title">next</span></span>...<br></code></pre></td></tr></table></figure><p><strong>跳出双重循环</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++ {<br><span class="hljs-keyword">for</span> j := <span class="hljs-number">0</span>; j < <span class="hljs-number">5</span>; j++ {<br><span class="hljs-keyword">if</span> i == <span class="hljs-number">2</span> && j == <span class="hljs-number">2</span> {<br><span class="hljs-keyword">goto</span> LABEL1<br>}<br>}<br>}<br>LABEL1:<br>fmt.Println(<span class="hljs-string">"label1"</span>)<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>f()<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight llvm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs llvm"><span class="hljs-type">label</span><span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h1 id="-4"><a href="#-4" class="headerlink" title=""></a></h1><h1 id="-5"><a href="#-5" class="headerlink" title=""></a></h1>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-05-格式化输出</title>
<link href="/2024/08/13/golang-05-print/"/>
<url>/2024/08/13/golang-05-print/</url>
<content type="html"><![CDATA[<h1 id="格式化输出"><a href="#格式化输出" class="headerlink" title="格式化输出"></a>格式化输出</h1><p>下面实例使用到的结构体</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> Website <span class="hljs-keyword">struct</span> {<br> Name <span class="hljs-type">string</span><br>}<br><span class="hljs-comment">// 定义结构体变量</span><br><span class="hljs-keyword">var</span> site = Website{Name:<span class="hljs-string">"duoke360"</span>}<br></code></pre></td></tr></table></figure><h2 id="占位符"><a href="#占位符" class="headerlink" title="占位符"></a>占位符</h2><p><strong>普通占位符</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%v相应值的默认格式。Printf(<span class="hljs-string">"%v"</span>, site),Printf(<span class="hljs-string">"%+v"</span>, site){duoke360},{Name:duoke360}<br>在打印结构体时,“加号”标记(%+v)会添加字段名<br>%#v相应值的Go语法表示Printf(<span class="hljs-string">"#v"</span>, site)main.Website{Name:<span class="hljs-string">"duoke360"</span>}<br>%T相应值的类型的Go语法表示Printf(<span class="hljs-string">"%T"</span>, site)main.Website<br>%%字面上的百分号,并非值的占位符Printf(<span class="hljs-string">"%%"</span>)%<br></code></pre></td></tr></table></figure><p><strong>布尔占位符</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%t单词 <span class="hljs-literal">true</span> 或 <span class="hljs-literal">false</span>。Printf(<span class="hljs-string">"%t"</span>, <span class="hljs-literal">true</span>)<span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><p><strong>整数占位符</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%b二进制表示 Printf(<span class="hljs-string">"%b"</span>, <span class="hljs-number">5</span>)<span class="hljs-number">101</span><br>%c相应Unicode码点所表示的字符 Printf(<span class="hljs-string">"%c"</span>, <span class="hljs-number">0x4E2D</span>)中<br>%d十进制表示Printf(<span class="hljs-string">"%d"</span>, <span class="hljs-number">0x12</span>)<span class="hljs-number">18</span><br>%o八进制表示Printf(<span class="hljs-string">"%o"</span>, <span class="hljs-number">10</span>)<span class="hljs-number">12</span><br>%q单引号围绕的字符字面值,由Go语法安全地转义Printf(<span class="hljs-string">"%q"</span>, <span class="hljs-number">0x4E2D</span>)<span class="hljs-string">'中'</span><br>%x十六进制表示,字母形式为小写 a-fPrintf(<span class="hljs-string">"%x"</span>, <span class="hljs-number">13</span>)d<br>%X十六进制表示,字母形式为大写 A-FPrintf(<span class="hljs-string">"%x"</span>, <span class="hljs-number">13</span>)D<br>%UUnicode格式:U+<span class="hljs-number">1234</span>,等同于 <span class="hljs-string">"U+%04X"</span>Printf(<span class="hljs-string">"%U"</span>, <span class="hljs-number">0x4E2D</span>)U+<span class="hljs-number">4E2</span>D<br></code></pre></td></tr></table></figure><p><strong>浮点数和复数的组成部分(实部和虚部)</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%b无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat<br>的 <span class="hljs-string">'b'</span> 转换格式一致。例如 <span class="hljs-number">-123456</span>p<span class="hljs-number">-78</span><br>%e科学计数法,例如 <span class="hljs-number">-1234.456e+78</span>Printf(<span class="hljs-string">"%e"</span>, <span class="hljs-number">10.2</span>)<span class="hljs-number">1.020000e+01</span><br>%E科学计数法,例如 <span class="hljs-number">-1234.456E+78</span>Printf(<span class="hljs-string">"%e"</span>, <span class="hljs-number">10.2</span>)<span class="hljs-number">1.020000E+01</span><br>%f有小数点而无指数,例如 <span class="hljs-number">123.456</span>Printf(<span class="hljs-string">"%f"</span>, <span class="hljs-number">10.2</span>)<span class="hljs-number">10.200000</span><br>%g根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的<span class="hljs-number">0</span>)输出Printf(<span class="hljs-string">"%g"</span>, <span class="hljs-number">10.20</span>)<span class="hljs-number">10.2</span><br>%G根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的<span class="hljs-number">0</span>)输出Printf(<span class="hljs-string">"%G"</span>, <span class="hljs-number">10.20</span>+<span class="hljs-number">2i</span>)(<span class="hljs-number">10.2</span>+<span class="hljs-number">2i</span>)<br></code></pre></td></tr></table></figure><p><strong>字符串与字节切片</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%s输出字符串表示(<span class="hljs-type">string</span>类型或[]<span class="hljs-type">byte</span>)Printf(<span class="hljs-string">"%s"</span>, []<span class="hljs-type">byte</span>(<span class="hljs-string">"多课网"</span>))多课网<br>%q双引号围绕的字符串,由Go语法安全地转义Printf(<span class="hljs-string">"%q"</span>, <span class="hljs-string">"多课网"</span>)<span class="hljs-string">"多课网"</span><br>%x十六进制,小写字母,每字节两个字符Printf(<span class="hljs-string">"%x"</span>, <span class="hljs-string">"golang"</span>)<span class="hljs-number">676</span>f6c616e67<br>%X十六进制,大写字母,每字节两个字符Printf(<span class="hljs-string">"%X"</span>, <span class="hljs-string">"golang"</span>)<span class="hljs-number">676</span>F6C616E67<br></code></pre></td></tr></table></figure><p><strong>指针</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go">占位符说明举例输出<br>%p十六进制表示,前缀 <span class="hljs-number">0</span>xPrintf(<span class="hljs-string">"%p"</span>, &site)<span class="hljs-number">0x4f57f0</span><br></code></pre></td></tr></table></figure><h2 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> user <span class="hljs-keyword">struct</span> {<br>name <span class="hljs-type">string</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>u := user{<span class="hljs-string">"guo"</span>}<br><span class="hljs-comment">//Printf 格式化输出</span><br>fmt.Printf(<span class="hljs-string">"% + v\n"</span>, u) <span class="hljs-comment">//格式化输出结构</span><br>fmt.Printf(<span class="hljs-string">"%#v\n"</span>, u) <span class="hljs-comment">//输出值的 Go 语言表示方法</span><br>fmt.Printf(<span class="hljs-string">"%T\n"</span>, u) <span class="hljs-comment">//输出值的类型的 Go 语言表示</span><br>fmt.Printf(<span class="hljs-string">"%t\n"</span>, <span class="hljs-literal">true</span>) <span class="hljs-comment">//输出值的 true 或 false</span><br>fmt.Printf(<span class="hljs-string">"%b\n"</span>, <span class="hljs-number">1024</span>) <span class="hljs-comment">//二进制表示</span><br>fmt.Printf(<span class="hljs-string">"%c\n"</span>, <span class="hljs-number">11111111</span>) <span class="hljs-comment">//数值对应的 Unicode 编码字符</span><br>fmt.Printf(<span class="hljs-string">"%d\n"</span>, <span class="hljs-number">10</span>) <span class="hljs-comment">//十进制表示</span><br>fmt.Printf(<span class="hljs-string">"%o\n"</span>, <span class="hljs-number">8</span>) <span class="hljs-comment">//八进制表示</span><br>fmt.Printf(<span class="hljs-string">"%q\n"</span>, <span class="hljs-number">22</span>) <span class="hljs-comment">//转化为十六进制并附上单引号</span><br>fmt.Printf(<span class="hljs-string">"%x\n"</span>, <span class="hljs-number">1223</span>) <span class="hljs-comment">//十六进制表示,用a-f表示</span><br>fmt.Printf(<span class="hljs-string">"%X\n"</span>, <span class="hljs-number">1223</span>) <span class="hljs-comment">//十六进制表示,用A-F表示</span><br>fmt.Printf(<span class="hljs-string">"%U\n"</span>, <span class="hljs-number">1233</span>) <span class="hljs-comment">//Unicode表示</span><br>fmt.Printf(<span class="hljs-string">"%b\n"</span>, <span class="hljs-number">12.34</span>) <span class="hljs-comment">//无小数部分,两位指数的科学计数法6946802425218990p-49</span><br>fmt.Printf(<span class="hljs-string">"%e\n"</span>, <span class="hljs-number">12.345</span>) <span class="hljs-comment">//科学计数法,e表示</span><br>fmt.Printf(<span class="hljs-string">"%E\n"</span>, <span class="hljs-number">12.34455</span>) <span class="hljs-comment">//科学计数法,E表示</span><br>fmt.Printf(<span class="hljs-string">"%f\n"</span>, <span class="hljs-number">12.3456</span>) <span class="hljs-comment">//有小数部分,无指数部分</span><br>fmt.Printf(<span class="hljs-string">"%g\n"</span>, <span class="hljs-number">12.3456</span>) <span class="hljs-comment">//根据实际情况采用%e或%f输出</span><br>fmt.Printf(<span class="hljs-string">"%G\n"</span>, <span class="hljs-number">12.3456</span>) <span class="hljs-comment">//根据实际情况采用%E或%f输出</span><br>fmt.Printf(<span class="hljs-string">"%s\n"</span>, <span class="hljs-string">"wqdew"</span>) <span class="hljs-comment">//直接输出字符串或者[]byte</span><br>fmt.Printf(<span class="hljs-string">"%q\n"</span>, <span class="hljs-string">"dedede"</span>) <span class="hljs-comment">//双引号括起来的字符串</span><br>fmt.Printf(<span class="hljs-string">"%x\n"</span>, <span class="hljs-string">"abczxc"</span>) <span class="hljs-comment">//每个字节用两字节十六进制表示,a-f表示</span><br>fmt.Printf(<span class="hljs-string">"%X\n"</span>, <span class="hljs-string">"asdzxc"</span>) <span class="hljs-comment">//每个字节用两字节十六进制表示,A-F表示</span><br>fmt.Printf(<span class="hljs-string">"%p\n"</span>, <span class="hljs-number">0x123</span>) <span class="hljs-comment">//0x开头的十六进制数表示</span><br>}<br></code></pre></td></tr></table></figure><h1 id=""><a href="#" class="headerlink" title=""></a></h1><h1 id="运算符"><a href="#运算符" class="headerlink" title="运算符"></a>运算符</h1><p>Go 语言内置的运算符有:</p><ol><li>算术运算符</li><li>关系运算符</li><li>逻辑运算符</li><li>位运算符</li><li>赋值运算符</li></ol><h2 id="算术运算符"><a href="#算术运算符" class="headerlink" title="算术运算符"></a>算术运算符</h2><table><thead><tr><th align="left">运算符</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">+</td><td align="left">相加</td></tr><tr><td align="left">-</td><td align="left">相减</td></tr><tr><td align="left">*</td><td align="left">相乘</td></tr><tr><td align="left">/</td><td align="left">相除</td></tr><tr><td align="left">%</td><td align="left">求余</td></tr></tbody></table><p><strong>注意:</strong> <code>++</code>(自增)和<code>--</code>(自减)在Go语言中是单独的语句,并不是运算符。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">100</span><br>b := <span class="hljs-number">10</span><br><br>fmt.Printf(<span class="hljs-string">"(a + b): %v\n"</span>, (a + b))<br>fmt.Printf(<span class="hljs-string">"(a - b): %v\n"</span>, (a - b))<br>fmt.Printf(<span class="hljs-string">"(a * b): %v\n"</span>, (a * b))<br>fmt.Printf(<span class="hljs-string">"(a / b): %v\n"</span>, (a / b))<br>fmt.Printf(<span class="hljs-string">"(a %% b): %v\n"</span>, (a % b))<br><br>a++<br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>b--<br>fmt.Printf(<span class="hljs-string">"b: %v\n"</span>, b)<br>}<br></code></pre></td></tr></table></figure><h2 id="关系运算符"><a href="#关系运算符" class="headerlink" title="关系运算符"></a>关系运算符</h2><table><thead><tr><th align="left">运算符</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">==</td><td align="left">检查两个值是否相等,如果相等返回 True 否则返回 False。</td></tr><tr><td align="left">!=</td><td align="left">检查两个值是否不相等,如果不相等返回 True 否则返回 False。</td></tr><tr><td align="left">></td><td align="left">检查左边值是否大于右边值,如果是返回 True 否则返回 False。</td></tr><tr><td align="left">>=</td><td align="left">检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。</td></tr><tr><td align="left"><</td><td align="left">检查左边值是否小于右边值,如果是返回 True 否则返回 False。</td></tr><tr><td align="left"><=</td><td align="left">检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">1</span><br>b := <span class="hljs-number">2</span><br><br>fmt.Printf(<span class="hljs-string">"(a > b): %v\n"</span>, (a > b))<br>fmt.Printf(<span class="hljs-string">"(a < b): %v\n"</span>, (a < b))<br>fmt.Printf(<span class="hljs-string">"(a >= b): %v\n"</span>, (a >= b))<br>fmt.Printf(<span class="hljs-string">"(a <= b): %v\n"</span>, (a <= b))<br>fmt.Printf(<span class="hljs-string">"(a == b): %v\n"</span>, (a == b))<br>fmt.Printf(<span class="hljs-string">"(a != b): %v\n"</span>, (a != b))<br>}<br></code></pre></td></tr></table></figure><h2 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h2><table><thead><tr><th align="left">运算符</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">&&</td><td align="left">逻辑 AND 运算符。 如果两边的操作数都是 True,则为 True,否则为 False。</td></tr><tr><td align="left">||</td><td align="left">逻辑 OR 运算符。 如果两边的操作数有一个 True,则为 True,否则为 False。</td></tr><tr><td align="left">!</td><td align="left">逻辑 NOT 运算符。 如果条件为 True,则为 False,否则为 True。</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-literal">true</span><br>b := <span class="hljs-literal">false</span><br><br>fmt.Printf(<span class="hljs-string">"(a && b): %v\n"</span>, (a && b))<br>fmt.Printf(<span class="hljs-string">"(a || b): %v\n"</span>, (a || b))<br>fmt.Printf(<span class="hljs-string">"(!a): %v\n"</span>, (!a))<br>fmt.Printf(<span class="hljs-string">"(!b): %v\n"</span>, (!b))<br>}<br></code></pre></td></tr></table></figure><h2 id="位运算符"><a href="#位运算符" class="headerlink" title="位运算符"></a>位运算符</h2><p>位运算符对整数在内存中的二进制位进行操作。</p><table><thead><tr><th align="left">运算符</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">&</td><td align="left">参与运算的两数各对应的二进位相与。 (两位均为1才为1)</td></tr><tr><td align="left">|</td><td align="left">参与运算的两数各对应的二进位相或。 (两位有一个为1就为1)</td></tr><tr><td align="left">^</td><td align="left">参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 (两位不一样则为1)</td></tr><tr><td align="left"><<</td><td align="left">左移n位就是乘以2的n次方。 “a<<b”是把a的各二进位全部左移b位,高位丢弃,低位补0。</td></tr><tr><td align="left">>></td><td align="left">右移n位就是除以2的n次方。 “a>>b”是把a的各二进位全部右移b位。</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>a := <span class="hljs-number">4</span> <span class="hljs-comment">// 二进制 100</span><br>fmt.Printf(<span class="hljs-string">"a: %b\n"</span>, a)<br>b := <span class="hljs-number">8</span> <span class="hljs-comment">// 二进制 1000</span><br>fmt.Printf(<span class="hljs-string">"b: %b\n"</span>, b)<br><br>fmt.Printf(<span class="hljs-string">"(a & b): %v, %b \n"</span>, (a & b), (a & b))<br>fmt.Printf(<span class="hljs-string">"(a | b): %v, %b\n"</span>, (a | b), (a | b))<br>fmt.Printf(<span class="hljs-string">"(a ^ b): %v, %b\n"</span>, (a ^ b), (a ^ b))<br>fmt.Printf(<span class="hljs-string">"(a << 2): %v, %b\n"</span>, (a << <span class="hljs-number">2</span>), (a << <span class="hljs-number">2</span>))<br>fmt.Printf(<span class="hljs-string">"(b >> 2): %v, %b\n"</span>, (b >> <span class="hljs-number">2</span>), (b >> <span class="hljs-number">2</span>))<br>}<br></code></pre></td></tr></table></figure><h2 id="赋值运算符"><a href="#赋值运算符" class="headerlink" title="赋值运算符"></a>赋值运算符</h2><table><thead><tr><th align="left">运算符</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">=</td><td align="left">简单的赋值运算符,将一个表达式的值赋给一个左值</td></tr><tr><td align="left">+=</td><td align="left">相加后再赋值</td></tr><tr><td align="left">-=</td><td align="left">相减后再赋值</td></tr><tr><td align="left">*=</td><td align="left">相乘后再赋值</td></tr><tr><td align="left">/=</td><td align="left">相除后再赋值</td></tr><tr><td align="left">%=</td><td align="left">求余后再赋值</td></tr><tr><td align="left"><<=</td><td align="left">左移后赋值</td></tr><tr><td align="left">>>=</td><td align="left">右移后赋值</td></tr><tr><td align="left">&=</td><td align="left">按位与后赋值</td></tr><tr><td align="left">|=</td><td align="left">按位或后赋值</td></tr><tr><td align="left">^=</td><td align="left">按位异或后赋值</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a <span class="hljs-type">int</span><br>a = <span class="hljs-number">100</span><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>a += <span class="hljs-number">1</span> <span class="hljs-comment">// a = a + 1</span><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>a -= <span class="hljs-number">1</span> <span class="hljs-comment">// a = a -1</span><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>a *= <span class="hljs-number">2</span> <span class="hljs-comment">// a = a * 2</span><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>a /= <span class="hljs-number">2</span> <span class="hljs-comment">// a = a / 2</span><br>fmt.Printf(<span class="hljs-string">"a: %v\n"</span>, a)<br>}<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-04-数据类型</title>
<link href="/2024/08/13/golang-04-datatype/"/>
<url>/2024/08/13/golang-04-datatype/</url>
<content type="html"><![CDATA[<h1 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h1><p>在 Go 编程语言中,数据类型用于声明函数和变量。</p><p>数据类型的出现是为了把数据分成所需<strong>内存大小</strong>不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。</p><p>Go 语言按类别有以下几种数据类型:</p><table><thead><tr><th align="left">序号</th><th align="left">类型和描述</th></tr></thead><tbody><tr><td align="left">1</td><td align="left"><strong>布尔型</strong> 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。</td></tr><tr><td align="left">2</td><td align="left"><strong>数字类型</strong> 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。</td></tr><tr><td align="left">3</td><td align="left"><strong>字符串类型:</strong> 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。</td></tr><tr><td align="left">4</td><td align="left"><strong>派生类型:</strong> 包括:(a) 指针类型(Pointer)(b) 数组类型(c) 结构化类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型(interface)(h) Map 类型</td></tr></tbody></table><h2 id="数字类型"><a href="#数字类型" class="headerlink" title="数字类型"></a>数字类型</h2><p>Go 也有基于架构的类型,例如:int、uint 和 uintptr。</p><table><thead><tr><th align="left">序号</th><th align="left">类型和描述</th></tr></thead><tbody><tr><td align="left">1</td><td align="left"><strong>uint8</strong> 无符号 8 位整型 (0 到 255)</td></tr><tr><td align="left">2</td><td align="left"><strong>uint16</strong> 无符号 16 位整型 (0 到 65535)</td></tr><tr><td align="left">3</td><td align="left"><strong>uint32</strong> 无符号 32 位整型 (0 到 4294967295)</td></tr><tr><td align="left">4</td><td align="left"><strong>uint64</strong> 无符号 64 位整型 (0 到 18446744073709551615)</td></tr><tr><td align="left">5</td><td align="left"><strong>int8</strong> 有符号 8 位整型 (-128 到 127)</td></tr><tr><td align="left">6</td><td align="left"><strong>int16</strong> 有符号 16 位整型 (-32768 到 32767)</td></tr><tr><td align="left">7</td><td align="left"><strong>int32</strong> 有符号 32 位整型 (-2147483648 到 2147483647)</td></tr><tr><td align="left">8</td><td align="left"><strong>int64</strong> 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)</td></tr></tbody></table><h3 id="浮点型"><a href="#浮点型" class="headerlink" title="浮点型"></a>浮点型</h3><table><thead><tr><th align="left">序号</th><th align="left">类型和描述</th></tr></thead><tbody><tr><td align="left">1</td><td align="left"><strong>float32</strong> IEEE-754 32位浮点型数</td></tr><tr><td align="left">2</td><td align="left"><strong>float64</strong> IEEE-754 64位浮点型数</td></tr><tr><td align="left">3</td><td align="left"><strong>complex64</strong> 32 位实数和虚数</td></tr><tr><td align="left">4</td><td align="left"><strong>complex128</strong> 64 位实数和虚数</td></tr></tbody></table><h3 id="其他数字类型"><a href="#其他数字类型" class="headerlink" title="其他数字类型"></a>其他数字类型</h3><p>以下列出了其他更多的数字类型:</p><table><thead><tr><th align="left">序号</th><th align="left">类型和描述</th></tr></thead><tbody><tr><td align="left">1</td><td align="left"><strong>byte</strong> 类似 uint8</td></tr><tr><td align="left">2</td><td align="left"><strong>rune</strong> 类似 int32</td></tr><tr><td align="left">3</td><td align="left"><strong>uint</strong> 32 或 64 位</td></tr><tr><td align="left">4</td><td align="left"><strong>int</strong> 与 uint 一样大小</td></tr><tr><td align="left">5</td><td align="left"><strong>uintptr</strong> 无符号整型,用于存放一个指针</td></tr></tbody></table><p>Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码。</p><p>Go 也有基于架构的类型,例如:<code>int</code>、<code>uint</code> 和 <code>uintptr</code>。</p><p>这些类型的长度都是根据运行程序所在的操作系统类型所决定的:</p><ul><li><code>int</code> 和 <code>uint</code> 在 32 位操作系统上,它们均使用 32 位(4 个字节),在 64 位操作系统上,它们均使用 64 位(8 个字节)。</li><li><code>uintptr</code> 的长度被设定为足够存放一个指针即可。</li></ul><p>Go 语言中没有 <code>float</code> 类型。(Go语言中只有 <code>float32</code> 和 <code>float64</code>)没有double类型。</p><p>与操作系统架构无关的类型都有固定的大小,并在类型的名称中就可以看出来:</p><p>整数:</p><ul><li>int8(-128 -> 127)</li><li>int16(-32768 -> 32767)</li><li>int32(-2,147,483,648 -> 2,147,483,647)</li><li>int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)</li></ul><p>无符号整数:</p><ul><li>uint8(0 -> 255)</li><li>uint16(0 -> 65,535)</li><li>uint32(0 -> 4,294,967,295)</li><li>uint64(0 -> 18,446,744,073,709,551,615)</li></ul><p>浮点型(IEEE-754 标准):</p><ul><li>float32(+- 1e-45 -> +- 3.4 * 1e38)</li><li>float64(+- 5 * 1e-324 -> 107 * 1e308)</li></ul><p>int 型是计算最快的一种类型。</p><p>整型的零值为 0,浮点型的零值为 0.0。</p><h3 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h3><p>下面实例演示了,各个数字类型的长度和取值范围</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"math"</span><br><span class="hljs-string">"unsafe"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> i8 <span class="hljs-type">int8</span><br><span class="hljs-keyword">var</span> i16 <span class="hljs-type">int16</span><br><span class="hljs-keyword">var</span> i32 <span class="hljs-type">int32</span><br><span class="hljs-keyword">var</span> i64 <span class="hljs-type">int64</span><br><span class="hljs-keyword">var</span> ui8 <span class="hljs-type">uint8</span><br><span class="hljs-keyword">var</span> ui16 <span class="hljs-type">uint16</span><br><span class="hljs-keyword">var</span> ui32 <span class="hljs-type">uint32</span><br><span class="hljs-keyword">var</span> ui64 <span class="hljs-type">uint64</span><br><br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, i8, unsafe.Sizeof(i8), math.MinInt8, math.MaxInt8)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, i16, unsafe.Sizeof(i16), math.MinInt16, math.MaxInt16)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, i32, unsafe.Sizeof(i32), math.MinInt32, math.MaxInt32)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, i64, unsafe.Sizeof(i64), math.MinInt64, math.MaxInt64)<br><br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, ui8, unsafe.Sizeof(ui8), <span class="hljs-number">0</span>, math.MaxUint8)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, ui16, unsafe.Sizeof(ui16), <span class="hljs-number">0</span>, math.MaxUint16)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, ui32, unsafe.Sizeof(ui32), <span class="hljs-number">0</span>, math.MaxUint32)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, ui64, unsafe.Sizeof(ui64), <span class="hljs-number">0</span>, <span class="hljs-type">uint64</span>(math.MaxUint64))<br><br><span class="hljs-keyword">var</span> f32 <span class="hljs-type">float32</span><br><span class="hljs-keyword">var</span> f64 <span class="hljs-type">float64</span><br><br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, f32, unsafe.Sizeof(f32), -math.MaxFloat32, math.MaxFloat32)<br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, f64, unsafe.Sizeof(f64), -math.MaxFloat64, math.MaxFloat64)<br><br><span class="hljs-keyword">var</span> ui <span class="hljs-type">uint</span><br>ui = <span class="hljs-type">uint</span>(math.MaxUint64) <span class="hljs-comment">//再+1会导致overflows错误</span><br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, ui, unsafe.Sizeof(ui), <span class="hljs-number">0</span>, ui)<br><br><span class="hljs-keyword">var</span> imax, imin <span class="hljs-type">int</span><br>imax = <span class="hljs-type">int</span>(math.MaxInt64) <span class="hljs-comment">//再+1会导致overflows错误</span><br>imin = <span class="hljs-type">int</span>(math.MinInt64) <span class="hljs-comment">//再-1会导致overflows错误</span><br><br>fmt.Printf(<span class="hljs-string">"%T %dB %v~%v\n"</span>, imax, unsafe.Sizeof(imax), imin, imax)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">int8</span> <span class="hljs-number">1</span>B -<span class="hljs-number">128</span>~<span class="hljs-number">127</span><br><span class="hljs-attribute">int16</span> <span class="hljs-number">2</span>B -<span class="hljs-number">32768</span>~<span class="hljs-number">32767</span><br><span class="hljs-attribute">int32</span> <span class="hljs-number">4</span>B -<span class="hljs-number">2147483648</span>~<span class="hljs-number">2147483647</span><br><span class="hljs-attribute">int64</span> <span class="hljs-number">8</span>B -<span class="hljs-number">9223372036854775808</span>~<span class="hljs-number">9223372036854775807</span><br><span class="hljs-attribute">uint8</span> <span class="hljs-number">1</span>B <span class="hljs-number">0</span>~<span class="hljs-number">255</span><br><span class="hljs-attribute">uint16</span> <span class="hljs-number">2</span>B <span class="hljs-number">0</span>~<span class="hljs-number">65535</span><br><span class="hljs-attribute">uint32</span> <span class="hljs-number">4</span>B <span class="hljs-number">0</span>~<span class="hljs-number">4294967295</span><br><span class="hljs-attribute">uint64</span> <span class="hljs-number">8</span>B <span class="hljs-number">0</span>~<span class="hljs-number">18446744073709551615</span><br><span class="hljs-attribute">float32</span> <span class="hljs-number">4</span>B -<span class="hljs-number">3</span>.<span class="hljs-number">4028234663852886</span>e+<span class="hljs-number">38</span>~<span class="hljs-number">3</span>.<span class="hljs-number">4028234663852886</span>e+<span class="hljs-number">38</span><br><span class="hljs-attribute">float64</span> <span class="hljs-number">8</span>B -<span class="hljs-number">1</span>.<span class="hljs-number">7976931348623157</span>e+<span class="hljs-number">308</span>~<span class="hljs-number">1</span>.<span class="hljs-number">7976931348623157</span>e+<span class="hljs-number">308</span><br><span class="hljs-attribute">uint</span> <span class="hljs-number">8</span>B <span class="hljs-number">0</span>~<span class="hljs-number">18446744073709551615</span><br><span class="hljs-attribute">int</span> <span class="hljs-number">8</span>B -<span class="hljs-number">9223372036854775808</span>~<span class="hljs-number">9223372036854775807</span><br></code></pre></td></tr></table></figure><h3 id="以二进制、八进制或十六进制浮点数的格式定义数字"><a href="#以二进制、八进制或十六进制浮点数的格式定义数字" class="headerlink" title="以二进制、八进制或十六进制浮点数的格式定义数字"></a>以二进制、八进制或十六进制浮点数的格式定义数字</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-comment">// 十进制</span><br><span class="hljs-keyword">var</span> a <span class="hljs-type">int</span> = <span class="hljs-number">10</span><br>fmt.Printf(<span class="hljs-string">"%d \n"</span>, a) <span class="hljs-comment">// 10</span><br>fmt.Printf(<span class="hljs-string">"%b \n"</span>, a) <span class="hljs-comment">// 1010 占位符%b表示二进制</span><br><br><span class="hljs-comment">// 八进制 以0开头</span><br><span class="hljs-keyword">var</span> b <span class="hljs-type">int</span> = <span class="hljs-number">077</span><br>fmt.Printf(<span class="hljs-string">"%o \n"</span>, b) <span class="hljs-comment">// 77</span><br><br><span class="hljs-comment">// 十六进制 以0x开头</span><br><span class="hljs-keyword">var</span> c <span class="hljs-type">int</span> = <span class="hljs-number">0xff</span><br>fmt.Printf(<span class="hljs-string">"%x \n"</span>, c) <span class="hljs-comment">// ff</span><br>fmt.Printf(<span class="hljs-string">"%X \n"</span>, c) <span class="hljs-comment">// FF</span><br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-number">10</span> <br><span class="hljs-number">1010</span> <br><span class="hljs-number">77</span> <br><span class="hljs-string">ff</span> <br><span class="hljs-string">FF</span> <br></code></pre></td></tr></table></figure><h3 id="浮点型-1"><a href="#浮点型-1" class="headerlink" title="浮点型"></a>浮点型</h3><p>Go语言支持两种浮点型数:<code>float32</code>和<code>float64</code>。这两种浮点型数据格式遵循<code>IEEE 754</code>标准: <code>float32</code> 的浮点数的最大范围约为 <code>3.4e38</code>,可以使用常量定义:<code>math.MaxFloat32</code>。 <code>float64</code> 的浮点数的最大范围约为 <code>1.8e308</code>,可以使用一个常量定义:<code>math.MaxFloat64</code>。</p><p>打印浮点数时,可以使用<code>fmt</code>包配合动词<code>%f</code>,代码如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"math"</span><br>)<br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> fmt.Printf(<span class="hljs-string">"%f\n"</span>, math.Pi)<br> fmt.Printf(<span class="hljs-string">"%.2f\n"</span>, math.Pi)<br>}<br></code></pre></td></tr></table></figure><p>复数</p><p>complex64和complex128</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> c1 <span class="hljs-type">complex64</span><br>c1 = <span class="hljs-number">1</span> + <span class="hljs-number">2i</span><br><span class="hljs-keyword">var</span> c2 <span class="hljs-type">complex128</span><br>c2 = <span class="hljs-number">2</span> + <span class="hljs-number">3i</span><br>fmt.Println(c1)<br>fmt.Println(c2)<br></code></pre></td></tr></table></figure><p>复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部和虚部为64位。</p><h3 id="小节"><a href="#小节" class="headerlink" title="小节"></a>小节</h3><ol><li>uint8类型就是byte类型,代表了ascll码字符集的一个字符</li><li>当处理中文,日文,韩文等符合字符时,使用的是rune类型(int32),也就是Unicode字符集(utf-8,utf16是编码规则)</li></ol><p>go语言中的布尔类型有两个常量值:<code>true</code>和<code>false</code>。布尔类型经常用在<strong>条件判断</strong>语句,或者<strong>循环语句</strong>。也可以用在<strong>逻辑表达式</strong>中。</p><h2 id="布尔类型"><a href="#布尔类型" class="headerlink" title="布尔类型"></a>布尔类型</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> b1 <span class="hljs-type">bool</span> = <span class="hljs-literal">true</span><br><span class="hljs-keyword">var</span> b2 <span class="hljs-type">bool</span> = <span class="hljs-literal">false</span><br><span class="hljs-keyword">var</span> b3 = <span class="hljs-literal">true</span><br><span class="hljs-keyword">var</span> b4 = <span class="hljs-literal">false</span><br><br>b5 := <span class="hljs-literal">true</span><br>b6 := <span class="hljs-literal">false</span><br><br>fmt.Printf(<span class="hljs-string">"b1: %v\n"</span>, b1)<br>fmt.Printf(<span class="hljs-string">"b2: %v\n"</span>, b2)<br>fmt.Printf(<span class="hljs-string">"b3: %v\n"</span>, b3)<br>fmt.Printf(<span class="hljs-string">"b4: %v\n"</span>, b4)<br>fmt.Printf(<span class="hljs-string">"b5: %v\n"</span>, b5)<br>fmt.Printf(<span class="hljs-string">"b6: %v\n"</span>, b6)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">b1:</span> <span class="hljs-literal">true</span><br><span class="hljs-attr">b2:</span> <span class="hljs-literal">false</span><br><span class="hljs-attr">b3:</span> <span class="hljs-literal">true</span><br><span class="hljs-attr">b4:</span> <span class="hljs-literal">false</span><br><span class="hljs-attr">b5:</span> <span class="hljs-literal">true</span><br><span class="hljs-attr">b6:</span> <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><h3 id="用在条件判断中"><a href="#用在条件判断中" class="headerlink" title="用在条件判断中"></a>用在条件判断中</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>age := <span class="hljs-number">18</span><br>ok := age >= <span class="hljs-number">18</span><br><span class="hljs-keyword">if</span> ok {<br>fmt.Println(<span class="hljs-string">"你已经成年"</span>)<br>} <span class="hljs-keyword">else</span> {<br>fmt.Println(<span class="hljs-string">"你还未成年"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">你已经成年<br></code></pre></td></tr></table></figure><h3 id="用在循环语句中"><a href="#用在循环语句中" class="headerlink" title="用在循环语句中"></a>用在循环语句中</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>count := <span class="hljs-number">10</span><br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < count; i++ {<br>fmt.Printf(<span class="hljs-string">"i: %v\n"</span>, i)<br>}<br>}<br></code></pre></td></tr></table></figure><h3 id="用在逻辑表达式中"><a href="#用在逻辑表达式中" class="headerlink" title="用在逻辑表达式中"></a>用在逻辑表达式中</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>age := <span class="hljs-number">18</span><br>gender := <span class="hljs-string">"男"</span><br><br><span class="hljs-keyword">if</span> age >= <span class="hljs-number">18</span> && gender == <span class="hljs-string">"男"</span> {<br>fmt.Println(<span class="hljs-string">"你是成年男子"</span>)<br>}<br>}<br></code></pre></td></tr></table></figure><blockquote><p>注意:不能使用<code>0</code>和非<code>0</code>表示真假</p></blockquote><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>i := <span class="hljs-number">1</span><br><span class="hljs-keyword">if</span> i {<br><span class="hljs-comment">// 编译错误</span><br>}<br>}<br></code></pre></td></tr></table></figure><h2 id="字符串类型"><a href="#字符串类型" class="headerlink" title="字符串类型"></a>字符串类型</h2><p>一个Go语言字符串是一个任意<strong>字节的常量序列</strong>。[] byte</p><h3 id="go语言字符串字面量"><a href="#go语言字符串字面量" class="headerlink" title="go语言字符串字面量"></a>go语言字符串字面量</h3><p>在Go语言中,字符串字面量使用双引号 <code>""</code> 或者反引号 <code>'</code> 来创建。双引号用来创建可解析的字符串,支持转义,但不能用来引用多行;反引号用来创建原生的字符串字面量,可能由多行组成,但不支持转义,并且可以包含除了反引号外其他所有字符。双引号创建可解析的字符串应用最广泛,反引号用来创建原生的字符串则多用于书写多行消息,HTML以及正则表达式。</p><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> str1 <span class="hljs-type">string</span> = <span class="hljs-string">"hello world"</span><br><span class="hljs-keyword">var</span> html <span class="hljs-type">string</span> = <br><html><br><head><title>hello golang</title><br></html><br><span class="hljs-string">`</span><br><span class="hljs-string"></span><br><span class="hljs-string">fmt.Printf("str1: %v\n", str1)</span><br><span class="hljs-string">fmt.Printf("html: %v\n", html)</span><br><span class="hljs-string">}</span><br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go">str1: hello world<br>html: <br><html><br><head><title>hello golang</title><br></html><br></code></pre></td></tr></table></figure><h3 id="go语言字符串连接"><a href="#go语言字符串连接" class="headerlink" title="go语言字符串连接"></a>go语言字符串连接</h3><p><strong>使用加号</strong></p><p>虽然Go语言中的字符串是不可变的,但是字符串支持 <code>+</code> 级联操作和<code>+=</code>追加操作,例如:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>name := <span class="hljs-string">"tom"</span><br>age := <span class="hljs-string">"20"</span><br>msg := name + <span class="hljs-string">" "</span> + age<br>fmt.Printf(<span class="hljs-string">"msg: %v\n"</span>, msg)<br>fmt.Println(<span class="hljs-string">"-------------"</span>)<br>msg = <span class="hljs-string">""</span><br>msg += name<br>msg += <span class="hljs-string">" "</span><br>msg += age<br>fmt.Printf(<span class="hljs-string">"msg: %v\n"</span>, msg)<br>}<br></code></pre></td></tr></table></figure><blockquote><p>golang 里面的字符串都是不可变的,每次运算都会产生一个新的字符串,所以会产生很多临时的无用的字符串,不仅没有用,还会给 gc 带来额外的负担,所以性能比较差</p></blockquote><p><strong>使用<code>fmt.Sprintf()</code>函数</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>name := <span class="hljs-string">"tom"</span><br>age := <span class="hljs-string">"20"</span><br>msg := fmt.Sprintf(<span class="hljs-string">"%s,%s"</span>, name, age)<br>fmt.Printf(<span class="hljs-string">"msg: %v\n"</span>, msg)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">msg: tom,<span class="hljs-number">20</span><br></code></pre></td></tr></table></figure><blockquote><p>内部使用 <code>[]byte</code> 实现,不像直接运算符这种会产生很多临时的字符串,但是内部的逻辑比较复杂,有很多额外的判断,还用到了 <code>interface</code>,所以性能也不是很好</p></blockquote><p><strong><code>strings.Join()</code></strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>name := <span class="hljs-string">"tom"</span><br>age := <span class="hljs-string">"20"</span><br>msg := strings.Join([]<span class="hljs-type">string</span>{name, age}, <span class="hljs-string">","</span>)<br>fmt.Printf(<span class="hljs-string">"msg: %v\n"</span>, msg)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">msg</span>: tom,<span class="hljs-number">20</span><br></code></pre></td></tr></table></figure><blockquote><p>join会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,但是本来没有,去构造这个数据的代价也不小</p></blockquote><p><strong><code>buffer.WriteString()</code></strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"bytes"</span><br><span class="hljs-string">"fmt"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> buffer bytes.Buffer<br>buffer.WriteString(<span class="hljs-string">"tom"</span>)<br>buffer.WriteString(<span class="hljs-string">","</span>)<br>buffer.WriteString(<span class="hljs-string">"20"</span>)<br>fmt.Printf(<span class="hljs-string">"buffer.String(): %v\n"</span>, buffer.String())<br>}<br></code></pre></td></tr></table></figure><blockquote><p>这个比较理想,可以当成可变字符使用,对内存的增长也有优化,如果能预估字符串的长度,还可以用 <code>buffer.Grow()</code> 接口来设置 capacity</p></blockquote><h3 id="go语言字符串转义字符"><a href="#go语言字符串转义字符" class="headerlink" title="go语言字符串转义字符"></a>go语言字符串转义字符</h3><p>Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。</p><table><thead><tr><th align="left">转义符</th><th align="left">含义</th></tr></thead><tbody><tr><td align="left"><code>\r</code></td><td align="left">回车符(返回行首)</td></tr><tr><td align="left"><code>\n</code></td><td align="left">换行符(直接跳到下一行的同列位置)</td></tr><tr><td align="left"><code>\t</code></td><td align="left">制表符</td></tr><tr><td align="left"><code>\'</code></td><td align="left">单引号</td></tr><tr><td align="left"><code>\"</code></td><td align="left">双引号</td></tr><tr><td align="left"><code>\\</code></td><td align="left">反斜杠</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>fmt.Print(<span class="hljs-string">"hello\tworld\n"</span>)<br>fmt.Print(<span class="hljs-string">"\"c:\\test\\\""</span>)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs lsl">helloworld<br><span class="hljs-string">"c:<span class="hljs-subst">\t</span>est<span class="hljs-subst">\"</span></span><br></code></pre></td></tr></table></figure><h3 id="go语言字符串切片操作"><a href="#go语言字符串切片操作" class="headerlink" title="go语言字符串切片操作"></a>go语言字符串切片操作</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>str := <span class="hljs-string">"hello world"</span><br>n := <span class="hljs-number">3</span><br>m := <span class="hljs-number">5</span><br>fmt.Println(str[n]) <span class="hljs-comment">//获取字符串索引位置为n的原始字节</span><br>fmt.Println(str[n:m]) <span class="hljs-comment">//截取得字符串索引位置为 n 到 m-1 的字符串</span><br>fmt.Println(str[n:]) <span class="hljs-comment">//截取得字符串索引位置为 n 到 len(s)-1 的字符串</span><br>fmt.Println(str[:m]) <span class="hljs-comment">//截取得字符串索引位置为 0 到 m-1 的字符串</span><br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs vim"><span class="hljs-number">108</span><br><span class="hljs-keyword">lo</span><br><span class="hljs-keyword">lo</span> world<br>hello<br></code></pre></td></tr></table></figure><h3 id="go语言字符串常用方法"><a href="#go语言字符串常用方法" class="headerlink" title="go语言字符串常用方法"></a>go语言字符串常用方法</h3><table><thead><tr><th align="left">方法</th><th align="left">介绍</th></tr></thead><tbody><tr><td align="left">len(str)</td><td align="left">求长度</td></tr><tr><td align="left">+或fmt.Sprintf</td><td align="left">拼接字符串</td></tr><tr><td align="left">strings.Split</td><td align="left">分割</td></tr><tr><td align="left">strings.contains</td><td align="left">判断是否包含</td></tr><tr><td align="left">strings.HasPrefix,strings.HasSuffix</td><td align="left">前缀/后缀判断</td></tr><tr><td align="left">strings.Index(),strings.LastIndex()</td><td align="left">子串出现的位置</td></tr><tr><td align="left">strings.Join(a[]string, sep string)</td><td align="left">join操作</td></tr></tbody></table><p><strong>实例</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>s := <span class="hljs-string">"hello world!"</span><br>fmt.Printf(<span class="hljs-string">"len(s): %v\n"</span>, <span class="hljs-built_in">len</span>(s))<br>fmt.Printf(<span class="hljs-string">"strings.Split(s, \"\"): %v\n"</span>, strings.Split(s, <span class="hljs-string">" "</span>))<br>fmt.Printf(<span class="hljs-string">"strings.Contains(s, \"hello\"): %v\n"</span>, strings.Contains(s, <span class="hljs-string">"hello"</span>))<br>fmt.Printf(<span class="hljs-string">"strings.HasPrefix(s, \"hello\"): %v\n"</span>, strings.HasPrefix(s, <span class="hljs-string">"hello"</span>))<br>fmt.Printf(<span class="hljs-string">"strings.HasSuffix(s, \"world!\"): %v\n"</span>, strings.HasSuffix(s, <span class="hljs-string">"world!"</span>))<br>fmt.Printf(<span class="hljs-string">"strings.Index(s, \"l\"): %v\n"</span>, strings.Index(s, <span class="hljs-string">"l"</span>))<br>fmt.Printf(<span class="hljs-string">"strings.LastIndex(s, \"l\"): %v\n"</span>, strings.LastIndex(s, <span class="hljs-string">"l"</span>))<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs stylus"><span class="hljs-function"><span class="hljs-title">len</span><span class="hljs-params">(s)</span></span>: <span class="hljs-number">14</span><br>strings<span class="hljs-selector-class">.Split</span>(s, <span class="hljs-string">""</span>): <span class="hljs-selector-attr">[hello world!]</span><br>strings<span class="hljs-selector-class">.Contains</span>(s, <span class="hljs-string">"hello"</span>): true<br>strings<span class="hljs-selector-class">.HasPrefix</span>(s, <span class="hljs-string">"hello"</span>): true<br>strings<span class="hljs-selector-class">.HasSuffix</span>(s, <span class="hljs-string">"world!"</span>): true<br>strings<span class="hljs-selector-class">.Index</span>(s, <span class="hljs-string">"l"</span>): <span class="hljs-number">2</span><br>strings<span class="hljs-selector-class">.LastIndex</span>(s, <span class="hljs-string">"l"</span>): <span class="hljs-number">9</span><br></code></pre></td></tr></table></figure><h3 id="byte和rune类型"><a href="#byte和rune类型" class="headerlink" title="byte和rune类型"></a>byte和rune类型</h3><p>组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> a = <span class="hljs-string">'华'</span><br><span class="hljs-keyword">var</span> b = <span class="hljs-string">'a'</span><br>fmt.Printf(<span class="hljs-string">"a: %v,%c\n"</span>, a, a)<br>fmt.Printf(<span class="hljs-string">"b: %v,%c\n"</span>, b, b)<br>}<br></code></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">a</span>: <span class="hljs-number">21326</span>,华<br><span class="hljs-attribute">b</span>: <span class="hljs-number">97</span>,a<br></code></pre></td></tr></table></figure><p>Go 语言的字符有以下两种:</p><ol><li><code>uint8</code>类型,或者叫 byte 型,代表了<code>ASCII码</code>的一个字符。</li><li><code>rune</code>类型,代表一个 <code>UTF-8字符</code>。</li></ol><p>当需要处理中文、日文或者其他复合字符时,则需要用到<code>rune</code>类型。<code>rune</code>类型实际是一个<code>int32</code>。</p><p>Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾。</p>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-03-iota</title>
<link href="/2024/08/12/golang-03-iota/"/>
<url>/2024/08/12/golang-03-iota/</url>
<content type="html"><![CDATA[<h2 id="iota"><a href="#iota" class="headerlink" title="iota"></a>iota</h2><p><code>iota</code>是go语言的常量计数器,只能在常量的表达式中使用。</p><p><strong><code>iota</code>在const关键字出现时将被重置为0。==const中每新增一行常量声明==将使<code>iota</code>计数一次(iota可理解为const语句块中的行索引)。 使用iota能简化定义,在定义枚举时很有用。</strong></p><p>举个例子:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> (<br>n1 = <span class="hljs-literal">iota</span> <span class="hljs-comment">//0</span><br>n2 <span class="hljs-comment">//1</span><br>n3 <span class="hljs-comment">//2</span><br>n4 <span class="hljs-comment">//3</span><br>)<br></code></pre></td></tr></table></figure><h3 id="几个常见的iota示例"><a href="#几个常见的iota示例" class="headerlink" title="几个常见的iota示例:"></a>几个常见的<code>iota</code>示例:</h3><p>使用<code>_</code>跳过某些值</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> (<br>n1 = <span class="hljs-literal">iota</span> <span class="hljs-comment">//0</span><br>n2 <span class="hljs-comment">//1</span><br>_<br>n4 <span class="hljs-comment">//3</span><br>)<br></code></pre></td></tr></table></figure><p><code>iota</code>声明中间插队</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> (<br>n1 = <span class="hljs-literal">iota</span> <span class="hljs-comment">//0</span><br>n2 = <span class="hljs-number">100</span> <span class="hljs-comment">//100</span><br>n3 = <span class="hljs-literal">iota</span> <span class="hljs-comment">//2</span><br>n4 <span class="hljs-comment">//3</span><br>)<br><span class="hljs-keyword">const</span> n5 = <span class="hljs-literal">iota</span> <span class="hljs-comment">//0</span><br></code></pre></td></tr></table></figure><p>定义数量级 (这里的<code><<</code>表示左移操作,<code>1<<10</code>表示将1的二进制表示向左移10位,也就是由<code>1</code>变成了<code>10000000000</code>,也就是十进制的1024。同理<code>2<<2</code>表示将2的二进制表示向左移2位,也就是由<code>10</code>变成了<code>1000</code>,也就是十进制的8。)</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> (<br>_ = <span class="hljs-literal">iota</span><br>KB = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-literal">iota</span>)<br>MB = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-literal">iota</span>)<br>GB = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-literal">iota</span>)<br>TB = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-literal">iota</span>)<br>PB = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-literal">iota</span>)<br>)<br></code></pre></td></tr></table></figure><p>多个<code>iota</code>定义在一行</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> (<br>a, b = <span class="hljs-literal">iota</span> + <span class="hljs-number">1</span>, <span class="hljs-literal">iota</span> + <span class="hljs-number">2</span> <span class="hljs-comment">//1,2 iota=0</span><br>c, d <span class="hljs-comment">//2,3 iota=3, 定义常量时,如果多行 第二行没有表达式,那么默认和上面的一行保持一致。</span><br> <span class="hljs-comment">// c,d = iota+1, iota+2</span><br>e, f <span class="hljs-comment">//3,4</span><br>)<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-02-变量</title>
<link href="/2024/08/12/golang-02-variable/"/>
<url>/2024/08/12/golang-02-variable/</url>
<content type="html"><![CDATA[<h1 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h1><h3 id="Go是一门区分大小写的语言"><a href="#Go是一门区分大小写的语言" class="headerlink" title="Go是一门区分大小写的语言"></a>Go是一门区分大小写的语言</h3><p>命名规则涉及变量、常量、全局函数、结构、接口、方法等的命名。 Go语言从语法层面进行了以下限定:任何需要对外暴露的名字必须以大写字母开头,不需要对外暴露的则应该以小写字母开头。</p><p>当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:<code>GetUserName</code>,那么使用这种形式的标识符的对象就<strong>可以被外部包的代码所使用</strong>(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 <code>public</code>); <strong>命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的</strong>(像面向对象语言中的 <code>private</code> )</p><h3 id="包名称"><a href="#包名称" class="headerlink" title="包名称"></a>包名称</h3><p>保持<code>package</code>的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为<strong>小写</strong>单词,不要使用下划线或者混合大小写。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> dao<br><span class="hljs-keyword">package</span> service<br></code></pre></td></tr></table></figure><h3 id="文件命名"><a href="#文件命名" class="headerlink" title="文件命名"></a>文件命名</h3><p>尽量采取有意义的文件名,简短,有意义,应该为<strong>小写</strong>单词,使用<strong>下划线</strong>分隔各个单词。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">customer_dao.<span class="hljs-keyword">go</span><br></code></pre></td></tr></table></figure><h3 id="结构体命名"><a href="#结构体命名" class="headerlink" title="结构体命名"></a>结构体命名</h3><p>采用<strong>驼峰命名法</strong>,首字母根据访问控制大写或者小写</p><p><code>struct</code> 申明和初始化格式采用多行,例如下面:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> CustomerOrder <span class="hljs-keyword">struct</span> {<br> Name <span class="hljs-type">string</span> <br> Address <span class="hljs-type">string</span><br>}<br>order := CustomerOrder{<span class="hljs-string">"tom"</span>, <span class="hljs-string">"北京海淀"</span>}<br></code></pre></td></tr></table></figure><h3 id="接口命名"><a href="#接口命名" class="headerlink" title="接口命名"></a>接口命名</h3><p>命名规则基本和上面的结构体类型</p><p>单个函数的结构名以 <strong>“er”</strong> 作为后缀,例如 <code>Reader</code> , <code>Writer</code> 。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> Reader <span class="hljs-keyword">interface</span> {<br> Read(p []<span class="hljs-type">byte</span>) (n <span class="hljs-type">int</span>, err <span class="hljs-type">error</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="变量命名"><a href="#变量命名" class="headerlink" title="变量命名"></a>变量命名</h3><p>和结构体类似,变量名称一般遵循<strong>驼峰法</strong>,首字母根据访问控制原则大写或者小写,但遇到特有名词时,需要遵循以下规则:</p><p>如果变量为私有,且特有名词为首个单词,则使用小写,如 appService 若变量类型为 bool 类型,则名称应以 Has, Is, Can 或 Allow 开头</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> isExist <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> hasConflict <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> canManage <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> allowGitHook <span class="hljs-type">bool</span><br></code></pre></td></tr></table></figure><h3 id="常量命名"><a href="#常量命名" class="headerlink" title="常量命名"></a>常量命名</h3><p>常量均需使用全部<strong>大写</strong>字母组成,并使用<strong>下划线分词</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> APP_URL = <span class="hljs-string">"https://www.duoke360.com"</span><br></code></pre></td></tr></table></figure><p>如果是枚举类型的常量,需要先创建相应类型:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> Scheme <span class="hljs-type">string</span><br><br><span class="hljs-keyword">const</span> (<br> HTTP Scheme = <span class="hljs-string">"http"</span><br> HTTPS Scheme = <span class="hljs-string">"https"</span><br>)<br></code></pre></td></tr></table></figure><h3 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h3><p>错误处理的原则就是不能丢弃任何有返回err的调用,不要使用 _ 丢弃,必须全部处理。接收到错误,要么返回err,或者使用log记录下来尽早return:一旦有错误发生,马上返回,尽量不要使用panic,除非你知道你在做什么,错误描述如果是英文必须为小写,不需要标点结尾,采用独立的错误流进行处理</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">// 错误写法</span><br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br> <span class="hljs-comment">// 错误处理</span><br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// 正常代码</span><br>}<br><br><span class="hljs-comment">// 正确写法</span><br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br> <span class="hljs-comment">// 错误处理</span><br> <span class="hljs-keyword">return</span> <span class="hljs-comment">// 或者继续</span><br>}<br><span class="hljs-comment">// 正常代码</span><br></code></pre></td></tr></table></figure><h3 id="单元测试"><a href="#单元测试" class="headerlink" title="单元测试"></a>单元测试</h3><p>单元测试文件名命名规范为 <code>example_test.go</code> 测试用例的函数名称必须以 <code>Test</code> 开头,例如:<code>TestExample</code> 每个重要的函数都要首先编写测试用例,测试用例和正规代码一起提交方便进行回归测试 。</p>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>golang-01-关键字 标识符</title>
<link href="/2024/08/12/golang-01-identifier/"/>
<url>/2024/08/12/golang-01-identifier/</url>
<content type="html"><![CDATA[<h1 id="Go语言关键字、标识符"><a href="#Go语言关键字、标识符" class="headerlink" title="Go语言关键字、标识符"></a>Go语言关键字、标识符</h1><h2 id="标识符"><a href="#标识符" class="headerlink" title="标识符"></a>标识符</h2><p>标识符的英文是<code>identifier</code>,通俗的讲,就是给变量、常量、函数、方法、结构体、数组、切片、接口起名字。</p><h3 id="标识符的组成"><a href="#标识符的组成" class="headerlink" title="标识符的组成"></a>标识符的组成</h3><ol><li>标识符由数字、字母和下划线(<code>_</code>)组成。123 abc _</li><li>只能以字母和下划线(<code>_</code>)<strong>开头</strong>。abc123 _sysVar 123abc</li><li>标识符区分大小写。 name Name NAME</li></ol><h3 id="举例说明标识符的命名"><a href="#举例说明标识符的命名" class="headerlink" title="举例说明标识符的命名"></a>举例说明标识符的命名</h3><p><strong>正确的命名</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> name <span class="hljs-type">string</span><br><span class="hljs-keyword">var</span> age <span class="hljs-type">int</span><br><span class="hljs-keyword">var</span> _sys <span class="hljs-type">int</span><br>}<br></code></pre></td></tr></table></figure><p><strong>错误的标识符</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> <span class="hljs-number">1</span>name <span class="hljs-type">string</span><br><span class="hljs-keyword">var</span> &age <span class="hljs-type">int</span><br><span class="hljs-keyword">var</span> !email<br>}<br></code></pre></td></tr></table></figure><h2 id="go语言关键字"><a href="#go语言关键字" class="headerlink" title="go语言关键字"></a>go语言关键字</h2><p>go语言提供了25个关键字,如下所示。</p><table><thead><tr><th align="left">break</th><th align="left">default</th><th align="left">func</th><th align="left">interface</th><th align="left">select</th></tr></thead><tbody><tr><td align="left">case</td><td align="left">defer</td><td align="left">go</td><td align="left">map</td><td align="left">struct</td></tr><tr><td align="left">chan</td><td align="left">else</td><td align="left">goto</td><td align="left">package</td><td align="left">switch</td></tr><tr><td align="left">const</td><td align="left">fallthrough</td><td align="left">if</td><td align="left">range</td><td align="left">type</td></tr><tr><td align="left">continue</td><td align="left">for</td><td align="left">import</td><td align="left">return</td><td align="left">var</td></tr></tbody></table><p>除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符,其中包含了基本类型的名称和一些基本的内置函数,见下表:</p><table><thead><tr><th align="left">append</th><th align="left">bool</th><th align="left">byte</th><th align="left">cap</th><th align="left">close</th><th align="left">complex</th><th align="left">complex64</th><th align="left">complex128</th><th align="left">uint16</th></tr></thead><tbody><tr><td align="left">copy</td><td align="left">false</td><td align="left">float32</td><td align="left">float64</td><td align="left">imag</td><td align="left">int</td><td align="left">int8</td><td align="left">int16</td><td align="left">uint32</td></tr><tr><td align="left">int32</td><td align="left">int64</td><td align="left">iota</td><td align="left">len</td><td align="left">make</td><td align="left">new</td><td align="left">nil</td><td align="left">panic</td><td align="left">uint64</td></tr><tr><td align="left">print</td><td align="left">println</td><td align="left">real</td><td align="left">recover</td><td align="left">string</td><td align="left">true</td><td align="left">uint</td><td align="left">uint8</td><td align="left">uintptr</td></tr></tbody></table><h2 id="go语言命名规范"><a href="#go语言命名规范" class="headerlink" title="go语言命名规范"></a>go语言命名规范</h2><h3 id="Go是一门区分大小写的语言"><a href="#Go是一门区分大小写的语言" class="headerlink" title="Go是一门区分大小写的语言"></a>Go是一门区分大小写的语言</h3><p>命名规则涉及变量、常量、全局函数、结构、接口、方法等的命名。 Go语言从语法层面进行了以下限定:任何需要对外暴露的名字必须以大写字母开头,不需要对外暴露的则应该以小写字母开头。</p><p>当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:<code>GetUserName</code>,那么使用这种形式的标识符的对象就<strong>可以被外部包的代码所使用</strong>(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 <code>public</code>); <strong>命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的</strong>(像面向对象语言中的 <code>private</code> )</p><h3 id="包名称"><a href="#包名称" class="headerlink" title="包名称"></a>包名称</h3><p>保持<code>package</code>的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为<strong>小写</strong>单词,不要使用下划线或者混合大小写。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> dao<br><span class="hljs-keyword">package</span> service<br></code></pre></td></tr></table></figure><h3 id="文件命名"><a href="#文件命名" class="headerlink" title="文件命名"></a>文件命名</h3><p>尽量采取有意义的文件名,简短,有意义,应该为<strong>小写</strong>单词,使用<strong>下划线</strong>分隔各个单词。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go">customer_dao.<span class="hljs-keyword">go</span><br></code></pre></td></tr></table></figure><h3 id="结构体命名"><a href="#结构体命名" class="headerlink" title="结构体命名"></a>结构体命名</h3><p>采用<strong>驼峰命名法</strong>,首字母根据访问控制大写或者小写</p><p><code>struct</code> 申明和初始化格式采用多行,例如下面:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> CustomerOrder <span class="hljs-keyword">struct</span> {<br> Name <span class="hljs-type">string</span> <br> Address <span class="hljs-type">string</span><br>}<br>order := CustomerOrder{<span class="hljs-string">"tom"</span>, <span class="hljs-string">"北京海淀"</span>}<br></code></pre></td></tr></table></figure><h3 id="接口命名"><a href="#接口命名" class="headerlink" title="接口命名"></a>接口命名</h3><p>命名规则基本和上面的结构体类型</p><p>单个函数的结构名以 <strong>“er”</strong> 作为后缀,例如 <code>Reader</code> , <code>Writer</code> 。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> Reader <span class="hljs-keyword">interface</span> {<br> Read(p []<span class="hljs-type">byte</span>) (n <span class="hljs-type">int</span>, err <span class="hljs-type">error</span>)<br>}<br></code></pre></td></tr></table></figure><h3 id="变量命名"><a href="#变量命名" class="headerlink" title="变量命名"></a>变量命名</h3><p>和结构体类似,变量名称一般遵循<strong>驼峰法</strong>,首字母根据访问控制原则大写或者小写,但遇到特有名词时,需要遵循以下规则:</p><p>如果变量为私有,且特有名词为首个单词,则使用小写,如 appService 若变量类型为 bool 类型,则名称应以 Has, Is, Can 或 Allow 开头</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">var</span> isExist <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> hasConflict <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> canManage <span class="hljs-type">bool</span><br><span class="hljs-keyword">var</span> allowGitHook <span class="hljs-type">bool</span><br></code></pre></td></tr></table></figure><h3 id="常量命名"><a href="#常量命名" class="headerlink" title="常量命名"></a>常量命名</h3><p>常量均需使用全部<strong>大写</strong>字母组成,并使用<strong>下划线分词</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">const</span> APP_URL = <span class="hljs-string">"https://www.duoke360.com"</span><br></code></pre></td></tr></table></figure><p>如果是枚举类型的常量,需要先创建相应类型:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">type</span> Scheme <span class="hljs-type">string</span><br><br><span class="hljs-keyword">const</span> (<br> HTTP Scheme = <span class="hljs-string">"http"</span><br> HTTPS Scheme = <span class="hljs-string">"https"</span><br>)<br></code></pre></td></tr></table></figure><h3 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h3><p>错误处理的原则就是不能丢弃任何有返回err的调用,不要使用 _ 丢弃,必须全部处理。接收到错误,要么返回err,或者使用log记录下来尽早return:一旦有错误发生,马上返回,尽量不要使用panic,除非你知道你在做什么,错误描述如果是英文必须为小写,不需要标点结尾,采用独立的错误流进行处理</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">// 错误写法</span><br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br> <span class="hljs-comment">// 错误处理</span><br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// 正常代码</span><br>}<br><br><span class="hljs-comment">// 正确写法</span><br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br> <span class="hljs-comment">// 错误处理</span><br> <span class="hljs-keyword">return</span> <span class="hljs-comment">// 或者继续</span><br>}<br><span class="hljs-comment">// 正常代码</span><br></code></pre></td></tr></table></figure><h3 id="单元测试"><a href="#单元测试" class="headerlink" title="单元测试"></a>单元测试</h3><p>单元测试文件名命名规范为 <code>example_test.go</code> 测试用例的函数名称必须以 <code>Test</code> 开头,例如:<code>TestExample</code> 每个重要的函数都要首先编写测试用例,测试用例和正规代码一起提交方便进行回归测试 。</p><h2 id="标识符-1"><a href="#标识符-1" class="headerlink" title="标识符"></a>标识符</h2><p>标识符的英文是<code>identifier</code>,通俗的讲,就是给变量、常量、函数、方法、结构体、数组、切片、接口起名字。</p><h3 id="标识符的组成-1"><a href="#标识符的组成-1" class="headerlink" title="标识符的组成"></a>标识符的组成</h3><ol><li>标识符由数字、字母和下划线(<code>_</code>)组成。123 abc _</li><li>只能以字母和下划线(<code>_</code>)<strong>开头</strong>。abc123 _sysVar 123abc</li><li>标识符区分大小写。 name Name NAME</li></ol><h3 id="举例说明标识符的命名-1"><a href="#举例说明标识符的命名-1" class="headerlink" title="举例说明标识符的命名"></a>举例说明标识符的命名</h3><p><strong>正确的命名</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> name <span class="hljs-type">string</span><br><span class="hljs-keyword">var</span> age <span class="hljs-type">int</span><br><span class="hljs-keyword">var</span> _sys <span class="hljs-type">int</span><br>}<br></code></pre></td></tr></table></figure><p><strong>错误的标识符</strong></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">var</span> <span class="hljs-number">1</span>name <span class="hljs-type">string</span><br><span class="hljs-keyword">var</span> &age <span class="hljs-type">int</span><br><span class="hljs-keyword">var</span> !email<br>}<br></code></pre></td></tr></table></figure><h2 id="go语言关键字-1"><a href="#go语言关键字-1" class="headerlink" title="go语言关键字"></a>go语言关键字</h2><p>go语言提供了25个关键字,如下所示。</p><table><thead><tr><th align="left">break</th><th align="left">default</th><th align="left">func</th><th align="left">interface</th><th align="left">select</th></tr></thead><tbody><tr><td align="left">case</td><td align="left">defer</td><td align="left">go</td><td align="left">map</td><td align="left">struct</td></tr><tr><td align="left">chan</td><td align="left">else</td><td align="left">goto</td><td align="left">package</td><td align="left">switch</td></tr><tr><td align="left">const</td><td align="left">fallthrough</td><td align="left">if</td><td align="left">range</td><td align="left">type</td></tr><tr><td align="left">continue</td><td align="left">for</td><td align="left">import</td><td align="left">return</td><td align="left">var</td></tr></tbody></table><p>除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符,其中包含了基本类型的名称和一些基本的内置函数,见下表:</p><table><thead><tr><th align="left">append</th><th align="left">bool</th><th align="left">byte</th><th align="left">cap</th><th align="left">close</th><th align="left">complex</th><th align="left">complex64</th><th align="left">complex128</th><th align="left">uint16</th></tr></thead><tbody><tr><td align="left">copy</td><td align="left">false</td><td align="left">float32</td><td align="left">float64</td><td align="left">imag</td><td align="left">int</td><td align="left">int8</td><td align="left">int16</td><td align="left">uint32</td></tr><tr><td align="left">int32</td><td align="left">int64</td><td align="left">iota</td><td align="left">len</td><td align="left">make</td><td align="left">new</td><td align="left">nil</td><td align="left">panic</td><td align="left">uint64</td></tr><tr><td align="left">print</td><td align="left">println</td><td align="left">real</td><td align="left">recover</td><td align="left">string</td><td align="left">true</td><td align="left">uint</td><td align="left">uint8</td><td align="left">uintptr</td></tr></tbody></table><h1 id=""><a href="#" class="headerlink" title=""></a></h1>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>Golang</tag>
</tags>
</entry>
<entry>
<title>k8s-01-container</title>
<link href="/2024/08/12/k8s-01-container/"/>
<url>/2024/08/12/k8s-01-container/</url>
<content type="html"><![CDATA[<h1 id="containerd"><a href="#containerd" class="headerlink" title="containerd"></a>containerd</h1><h2 id="containerd介绍"><a href="#containerd介绍" class="headerlink" title="containerd介绍"></a>containerd介绍</h2><p>Containerd是一个工业标准的容器运行时,重点是它简洁,健壮,便携,在Linux和window上可以作为一个<a href="https://so.csdn.net/so/search?q=%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B&spm=1001.2101.3001.7020">守护进程</a>运行,它可以管理主机系统上容器的完整的生命周期:镜像传输和存储,容器的执行和监控,低级别的存储和网络。<br>containerd和<a href="https://so.csdn.net/so/search?q=docker&spm=1001.2101.3001.7020">docker</a>不同,containerd重点是继承在大规模的系统中,例如kubernetes,而不是面向开发者,让开发者使用,更多的是容器运行时的概念,承载容器运行。</p><h3 id="Containerd-架构图"><a href="#Containerd-架构图" class="headerlink" title="Containerd 架构图"></a>Containerd 架构图</h3><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006339.png" alt="img"></p><h3 id="Containerd-作用"><a href="#Containerd-作用" class="headerlink" title="Containerd 作用"></a>Containerd 作用</h3><ul><li>管理容器的生命周期(从创建容器到销毁容器)</li><li>拉取/推送容器镜像</li><li>存储管理(管理镜像及容器数据的存储)</li><li>调用 runC 运行容器(与 runC 等容器运行时交互)</li><li>管理容器网络接口及网络</li></ul><h3 id="为什么需要-Containerd"><a href="#为什么需要-Containerd" class="headerlink" title="为什么需要 Containerd"></a>为什么需要 Containerd</h3><ul><li>继续从整体 docker 引擎中分离出的项目(开源项目的思路)</li><li>可以被 Kubernets CRI 等项目使用(通用化)</li><li>为广泛的行业合作打下基础(就像 runC 一样)</li></ul><h3 id="Containerd-的技术方向"><a href="#Containerd-的技术方向" class="headerlink" title="Containerd 的技术方向"></a>Containerd 的技术方向</h3><ul><li>简洁的基于 gRPC 的 API 和 client library</li><li>完整的 OCI 支持(runtime 和 image spec)</li><li>同时具备稳定性和高性能的定义良好的容器核心功能</li><li>一个解耦的系统(让 image、filesystem、runtime 解耦合),实现插件式的扩展和重用</li></ul><p>下图展示了 containerd 的技术架构<br><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006029.png" alt="img"><br>在架构设计和实现方面,核心开发人员在他们的博客里提到了通过反思 graphdriver 的实现,他们将 containerd 设计成了 snapshotter 的模式,这也使得 containerd 对于 overlay 文件系、snapshot 文件系统的支持比较好。<br>storage、metadata 和 runtime 的三大块划分非常清晰,通过抽象出 events 的设计,containerd 也得以将网络层面的复杂度交给了上层处理,仅提供 network namespace 相关的一些接口添加和配置 API。这样做的好处无疑是巨大的,保留最小功能集合的纯粹和高效,而将更多的复杂性及灵活性交给了插件及上层系统。</p><h3 id="Containerd-的愿景目标"><a href="#Containerd-的愿景目标" class="headerlink" title="Containerd 的愿景目标"></a>Containerd 的愿景目标</h3><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006875.png" alt="img"></p><p>当 containerd 和 runC 成为标准化容器服务的基石后,上层的应用就可以直接建立在 containerd 和 runC 之上。上图中展示的容器平台都已经支持 containerd 和 runC 的组合了,相信接下来会有更多类似的容器平台出现。<br>注意: Containerd 被设计成嵌入到一个更大的系统中,而不是直接由开发人员或终端用户使用。所以 containerd 具有宏大的愿景</p><h2 id="安装containerd"><a href="#安装containerd" class="headerlink" title="安装containerd"></a>安装containerd</h2><h3 id="安装containerd-1"><a href="#安装containerd-1" class="headerlink" title="安装containerd"></a>安装containerd</h3><h4 id="检测libseccomp版本"><a href="#检测libseccomp版本" class="headerlink" title="检测libseccomp版本"></a>检测libseccomp版本</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 一般是需要2.4版本的,自行升级</span><br>rpm -qa | grep libseccomp<br></code></pre></td></tr></table></figure><h4 id="下载软件包"><a href="#下载软件包" class="headerlink" title="下载软件包"></a>下载软件包</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">curl -L https://github.com/containerd/containerd/releases/download/v1.6.0/cri-containerd-cni-1.6.0-linux-amd64.tar.gz -O cri-containerd-cni-1.6.0-linux-amd64.tar.gz<br></code></pre></td></tr></table></figure><h4 id="解压文件"><a href="#解压文件" class="headerlink" title="解压文件"></a>解压文件</h4><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">tar</span> -xf cri-containerd-cni-<span class="hljs-number">1</span>.<span class="hljs-number">6</span>.<span class="hljs-number">0</span>-linux-amd64.tar.gz -C /<br></code></pre></td></tr></table></figure><p>containerd的文件格式可直接解压到/,如果不需要做一些特殊更改。下面的步骤只是为了更加详细的了解一下。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 用于解压后的文件临时存放</span><br><span class="hljs-built_in">mkdir</span> -p ~/containerd<br>tar -xf cri-containerd-cni-1.6.0-linux-amd64.tar.gz -C ~/containerd<br><br><span class="hljs-comment"># 文件内容详情</span><br><br>$ ll<br>总用量 0<br>drwxr-xr-x 4 root root 51 2月 16 2022 etc<br>drwxr-xr-x 4 root root 35 2月 16 2022 opt<br>drwxr-xr-x 3 root root 19 2月 16 2022 usr<br><br>$ tree<br>.<br>├── etc<br>│ ├── cni<br>│ │ └── net.d<br>│ │ └── 10-containerd-net.conflist<br>│ ├── crictl.yaml<br>│ └── systemd<br>│ └── system<br>│ └── containerd.service<br>├── opt<br>│ ├── cni<br>│ │ └── bin<br>│ │ ├── bandwidth<br>│ │ ├── bridge<br>│ │ ├── dhcp<br>│ │ ├── firewall<br>│ │ ├── host-device<br>│ │ ├── host-local<br>│ │ ├── ipvlan<br>│ │ ├── loopback<br>│ │ ├── macvlan<br>│ │ ├── portmap<br>│ │ ├── ptp<br>│ │ ├── sbr<br>│ │ ├── static<br>│ │ ├── tuning<br>│ │ ├── vlan<br>│ │ └── vrf<br>│ └── containerd<br>│ └── cluster<br>│ ├── gce<br>│ │ ├── cloud-init<br>│ │ │ ├── master.yaml<br>│ │ │ └── node.yaml<br>│ │ ├── cni.template<br>│ │ ├── configure.sh<br>│ │ └── <span class="hljs-built_in">env</span><br>│ └── version<br>└── usr<br> └── <span class="hljs-built_in">local</span><br> ├── bin<br> │ ├── containerd<br> │ ├── containerd-shim<br> │ ├── containerd-shim-runc-v1<br> │ ├── containerd-shim-runc-v2<br> │ ├── containerd-stress<br> │ ├── crictl<br> │ ├── critest<br> │ ├── ctd-decoder<br> │ └── ctr<br> └── sbin<br> └── runc<br><br>16 directories, 35 files<br></code></pre></td></tr></table></figure><h4 id="拷贝二进制文件"><a href="#拷贝二进制文件" class="headerlink" title="拷贝二进制文件"></a>拷贝二进制文件</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> ~/containerd<br><span class="hljs-built_in">cp</span> ~/containerd/usr/local/bin/* /usr/local/bin/<br></code></pre></td></tr></table></figure><h4 id="安装runc"><a href="#安装runc" class="headerlink" title="安装runc"></a>安装runc</h4><p>包里自带的runc依赖系统的呈然包含runC,但是依赖系统中的seccomp(安全计算模式,是一种限制容器调用系统资源的模式。所以会可能出现一些问题</p><blockquote><p>cp ./usr/local/sbin/runc /usr/local/sbin/</p><p>[root@containerd containerd]# runc -v<br>runc: symbol lookup error: runc: undefined symbol: seccomp_notify_respond</p></blockquote><p>下载:<a href="https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64">https://github.com/opencontainers/runc/releases/download/v1.1.10/runc.amd64</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mv</span> runc.amd64 runc<br><span class="hljs-built_in">chmod</span> +x runc<br><span class="hljs-built_in">mv</span> runc /usr/local/sbin/<br><br>runc -v<br>runc version 1.1.0<br>commit: v1.1.0-0-g067aaf85<br>spec: 1.0.2-dev<br>go: go1.17.6<br>libseccomp: 2.5.3<br></code></pre></td></tr></table></figure><h4 id="拷贝cni插件"><a href="#拷贝cni插件" class="headerlink" title="拷贝cni插件"></a>拷贝cni插件</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cp</span> -a ./opt/* /opt<br></code></pre></td></tr></table></figure><h4 id="生成配置文件"><a href="#生成配置文件" class="headerlink" title="生成配置文件"></a>生成配置文件</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 生成containerd配置</span><br><span class="hljs-built_in">mkdir</span> -p /etc/containerd<br>containerd config default > /etc/containerd/config.toml<br><br><span class="hljs-comment"># 修改配置</span><br>sed -i <span class="hljs-string">"s#SystemdCgroup = false#SystemdCgroup = true#"</span> /etc/containerd/config.toml<br>sed -i <span class="hljs-string">"s#k8s.gcr.io#registry.aliyuncs.com/google_containers#"</span> /etc/containerd/config.toml<br></code></pre></td></tr></table></figure><h4 id="添加服务启动文件"><a href="#添加服务启动文件" class="headerlink" title="添加服务启动文件"></a>添加服务启动文件</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 这是官方自带的配置文件,直接copy就行了</span><br><br>find ./ -name <span class="hljs-string">"containerd.service"</span><br>./etc/systemd/system/containerd.service<br><br><span class="hljs-built_in">cp</span> ./etc/systemd/system/containerd.service /etc/systemd/system/<br></code></pre></td></tr></table></figure><h4 id="执行启动"><a href="#执行启动" class="headerlink" title="执行启动"></a>执行启动</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment">#启动containerd</span><br>systemctl daemon-reload && systemctl <span class="hljs-built_in">enable</span> containerd --now<br>systemctl status containerd<br></code></pre></td></tr></table></figure><h3 id="安装nerdctl"><a href="#安装nerdctl" class="headerlink" title="安装nerdctl"></a>安装nerdctl</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment">#下载nerdctl</span><br>curl -L https://github.com/containerd/nerdctl/releases/download/v1.6.0/nerdctl-1.6.0-linux-amd64.tar.gz -O nerdctl-1.6.0-linux-amd64.tar.gz<br><br>tar zxvf nerdctl-1.6.0-linux-amd64.tar.gz -C /usr/local/sbin<br><br><span class="hljs-built_in">mkdir</span> -p /etc/nerdctl/<br><span class="hljs-built_in">cat</span> > /etc/nerdctl/nerdctl.toml << <span class="hljs-string">'EOF'</span><br>insecure_registry=<span class="hljs-literal">true</span><br>EOF<br></code></pre></td></tr></table></figure><h3 id="启动容器验证"><a href="#启动容器验证" class="headerlink" title="启动容器验证"></a>启动容器验证</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nerdctl -n test1 run -d -p 18080:80 --name test-nginx --restart=always docker.io/library/nginx:latest<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@containerd gce]# <span class="hljs-built_in">sudo</span> iptables -t nat -L -n -v | grep 18080<br> 0 0 CNI-HOSTPORT-SETMARK tcp -- * * 10.4.0.0/24 0.0.0.0/0 tcp dpt:18080<br> 1 60 CNI-HOSTPORT-SETMARK tcp -- * * 127.0.0.1 0.0.0.0/0 tcp dpt:18080<br> 1 60 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:18080 to:10.4.0.8:80<br> 1 60 CNI-DN-aafbf751fe0e2804fa740 tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* dnat name: <span class="hljs-string">"bridge"</span> <span class="hljs-built_in">id</span>: <span class="hljs-string">"test1-a3d18d252236e4b3a847da611543854caa44e2767650075965f98502d7f96304"</span> */ multiport dports 18080<br></code></pre></td></tr></table></figure><h3 id="安装buildkit"><a href="#安装buildkit" class="headerlink" title="安装buildkit"></a>安装buildkit</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment">#下载buildkit</span><br>curl -L https://github.com/moby/buildkit/releases/download/v0.9.3/buildkit-v0.9.3.linux-amd64.tar.gz -o buildkit-v0.9.3.linux-amd64.tar.gz<br><br>tar zxvf buildkit-v0.10.3.darwin-amd64.tar.gz -C /usr/local/<br><br><span class="hljs-comment">#/etc/buildkit/buildkitd.toml为buildkitd默认配置</span><br><br><span class="hljs-built_in">mkdir</span> -p /etc/buildkit/<br><span class="hljs-built_in">cat</span> > /etc/buildkit/buildkitd.toml << <span class="hljs-string">'EOF'</span><br><br>debug = <span class="hljs-literal">true</span><br><span class="hljs-comment"># root is where all buildkit state is stored.</span><br>root = <span class="hljs-string">"/var/lib/buildkit"</span><br><span class="hljs-comment"># insecure-entitlements allows insecure entitlements, disabled by default.</span><br>insecure-entitlements = [ <span class="hljs-string">"network.host"</span>, <span class="hljs-string">"security.insecure"</span> ]<br><br>[worker.oci]<br> enabled = <span class="hljs-literal">true</span><br> platforms = [ <span class="hljs-string">"linux/amd64"</span>, <span class="hljs-string">"linux/arm64"</span> ]<br> snapshotter = <span class="hljs-string">"auto"</span><br> rootless = <span class="hljs-literal">false</span><br> noProcessSandbox = <span class="hljs-literal">false</span><br> gc = <span class="hljs-literal">true</span><br> gckeepstorage = 9000<br> max-parallelism = 4<br><br> [[worker.oci.gcpolicy]]<br> keepBytes = 512000000<br> keepDuration = 172800<br> filters = [ <span class="hljs-string">"type==source.local"</span>, <span class="hljs-string">"type==exec.cachemount"</span>, <span class="hljs-string">"type==source.git.checkout"</span>]<br><br>[registry.<span class="hljs-string">"19.15.14.158:31104"</span>]<br> mirrors = [<span class="hljs-string">"19.15.14.158:31104"</span>]<br> http = <span class="hljs-literal">true</span> <span class="hljs-comment">#使用http协议</span><br> insecure = <span class="hljs-literal">true</span> <span class="hljs-comment">#不验证安全证书</span><br>[registry.<span class="hljs-string">"mmzwwwdocker.xxxxxx.com:31104"</span>]<br> mirrors = [<span class="hljs-string">"mmzwwwdocker.xxxxxxx.com:31104"</span>]<br> http = <span class="hljs-literal">true</span> <span class="hljs-comment">#使用http协议</span><br> insecure = <span class="hljs-literal">true</span> <span class="hljs-comment">#不验证安全证书</span><br>EOF<br><br><span class="hljs-built_in">cat</span> > /etc/systemd/system/buildkit.service << <span class="hljs-string">'EOF'</span><br>[Unit]<br>Description=BuildKit<br>Documentation=https://github.com/moby/buildkit<br><br>[Service]<br>ExecStart=/usr/local/bin/buildkitd --oci-worker=<span class="hljs-literal">false</span> --containerd-worker=<span class="hljs-literal">true</span><br><br>[Install]<br>WantedBy=multi-user.target<br>EOF<br><br><br>systemctl daemon-reload<br>systemctl <span class="hljs-built_in">enable</span> buildkit --now<br>systemctl status buildkit<br></code></pre></td></tr></table></figure><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> <span class="hljs-built_in">test</span><br><span class="hljs-built_in">cd</span> <span class="hljs-built_in">test</span><br><span class="hljs-built_in">cat</span> > Dockerfile << <span class="hljs-string">'EOF'</span><br>FROM alpine<br>EOF<br><br>docker build --platform arm64,amd64 -t test1 .<br><br>[+] Building 4.6s (7/7) FINISHED <br> => [internal] load build definition from Dockerfile 0.0s<br> => => transferring dockerfile: 49B 0.0s<br> => [internal] load .dockerignore 0.0s<br> => => transferring context: 2B 0.0s<br> => [linux/amd64 internal] load metadata <span class="hljs-keyword">for</span> docker.io/library/alpine:latest 0.6s<br> => [linux/arm64 internal] load metadata <span class="hljs-keyword">for</span> docker.io/library/alpine:latest 2.6s<br> => CACHED [linux/amd64 1/1] FROM docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 0.0s<br> => => resolve docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 0.0s<br> => [linux/arm64 1/1] FROM docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 1.7s<br> => => resolve docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 0.0s<br> => => sha256:9b3977197b4f2147bdd31e1271f811319dcd5c2fc595f14e81f5351ab6275b99 2.10MB / 2.72MB 1.9s<br> => exporting to oci image format 1.9s<br> => => exporting layers 0.0s<br> => => exporting manifest sha256:1bfa860f8991c3b6952fbb59493e8c346c4e46a78fff4099b4d95d87ad741283 0.0s<br> => => exporting config sha256:69d06718b798aebf8c13b1a53299d1f791f8118dcd0fa9a0a827bf2f595aa9ca 0.0s<br> => => exporting manifest sha256:e3b23b57855e132673409165a5a6559180c32d273399f13cf078163fea7398a0 0.0s<br> => => exporting config sha256:35e223a20dbce8c0b81d3257f8cad0c7b2b35d8e18eadfec7eeb7de86a472e7b 0.0s<br> => => exporting manifest list sha256:631ae1b627eb47a92dbaa80d1f2f4d38bd0b2b9196736076053e02689a27101c 0.0s<br> => => sending tarball 0.1s<br>unpacking docker.io/library/test1:latest (sha256:631ae1b627eb47a92dbaa80d1f2f4d38bd0b2b9196736076053e02689a27101c)...<span class="hljs-keyword">done</span><br><br>123456789101112131415161718192021222324252627282930<br></code></pre></td></tr></table></figure><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121825640.png" alt="在这里插入图片描述"></p><p>测试动行时</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -d -p 80:80 nginx<br><br>12<br></code></pre></td></tr></table></figure><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121825743.png" alt="在这里插入图片描述"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">iptables -t nat -nvL<br>1<br></code></pre></td></tr></table></figure><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121825023.png" alt="在这里插入图片描述"></p><h3 id="配置私有仓库"><a href="#配置私有仓库" class="headerlink" title="配置私有仓库"></a>配置私有仓库</h3><p>配置跳过kube.registry.local:5000这个仓库的https认证</p><p><code>vim /etc/containerd/config.toml</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><code class="hljs bash">version = 2<br>root = <span class="hljs-string">"/opt/lib/containerd"</span><br>state = <span class="hljs-string">"/run/containerd"</span><br>oom_score = 0<br><br>[grpc]<br> max_recv_message_size = 16777216<br> max_send_message_size = 16777216<br><br>[debug]<br> level = <span class="hljs-string">"info"</span><br><br>[metrics]<br> address = <span class="hljs-string">""</span><br> grpc_histogram = <span class="hljs-literal">false</span><br><br>[plugins]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>]<br> sandbox_image = <span class="hljs-string">"kube.registry.local:8081/library/pause:3.3"</span><br> max_container_log_line_size = -1<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.containerd]<br> default_runtime_name = <span class="hljs-string">"runc"</span><br> snapshotter = <span class="hljs-string">"overlayfs"</span><br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.containerd.runtimes]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.containerd.runtimes.runc]<br> runtime_type = <span class="hljs-string">"io.containerd.runc.v2"</span><br> runtime_engine = <span class="hljs-string">""</span><br> runtime_root = <span class="hljs-string">""</span><br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.containerd.runtimes.runc.options]<br> systemdCgroup = <span class="hljs-literal">true</span><br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors.<span class="hljs-string">"docker.io"</span>]<br> endpoint = [<span class="hljs-string">"https://registry-1.docker.io"</span>]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors.<span class="hljs-string">"kube.registry.local:5000"</span>]<br> endpoint = [<span class="hljs-string">"https://kube.registry.local:5000"</span>]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.configs]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.configs.<span class="hljs-string">"kube.registry.local:5000"</span>.tls]<br> insecure_skip_verify = <span class="hljs-literal">true</span><br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.headers]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors.<span class="hljs-string">"docker.io"</span>]<br> endpoint = [<span class="hljs-string">"https://registry-1.docker.io"</span>]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.mirrors.<span class="hljs-string">"harbor.kids.com"</span>]<br> endpoint = [<span class="hljs-string">"https://harbor.kids.com"</span>]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.tlss]<br> [plugins.<span class="hljs-string">"io.containerd.grpc.v1.cri"</span>.registry.tlss.<span class="hljs-string">"harbor.kids.com"</span>]<br> ca_file = <span class="hljs-string">"/home/data/cert/ca.pem"</span><br> cert_file = <span class="hljs-string">"/home/data/cert/harbor.pem"</span><br> key_file = <span class="hljs-string">"/home/data/cert/harbor-key.pem"</span><br></code></pre></td></tr></table></figure><h2 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h2><h3 id="弃用Docker后会有什么不同?"><a href="#弃用Docker后会有什么不同?" class="headerlink" title="弃用Docker后会有什么不同?"></a>弃用Docker后会有什么不同?</h3><p>Don’t Panic!随后又重点解释了几个大家最关心的问题,我们来分析下官方提到的这些方面:</p><ul><li>正常的 K8s 用户不会有任何影响</li><li>是的,生产环境中高版本的集群只需要把运行时从 docker 切换到其他的 runtime(如 containerd)即可。containerd 是 docker 中的一个底层组件,主要负责维护容器的<a href="https://so.csdn.net/so/search?q=%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F&spm=1001.2101.3001.7020">生命周期</a>,跟随 docker 经历了长期考验。同时 2019年初就从 CNCF 毕业,可以单独作为容器运行时用在集群中。TKE 也早在 2019 年就已经提供了 containerd 作为运行时选项,因此把 runtime 从 docker 转换到 containerd 是一个基本无痛的过程。CRI-O 是另一个常被提及的运行时组件,由 redhat 提供,比 containerd 更加轻量级,不过和 docker 的区别较大,可能转换时会有一些不同之处。</li><li>开发环境中通过docker build构建出来的镜像依然可以在集群中使用</li><li>镜像一直是容器生态的一大优势,虽然人们总是把镜像称之为“docker镜像”,但镜像早就成为了一种规范了。具体规范可以参考image-spec。在任何地方只要构建出符合 Image Spec 的镜像,就可以拿到其他符合 Image Spec 的容器运行时上运行。</li><li>在 Pod 中使用 DinD(Docker in Docker)的用户会受到影响</li><li>有些使用者会把 docker 的 socket (/run/docker.sock)挂载到 Pod 中,并在 Pod 中调用 docker 的 api 构建镜像或创建编译容器等,官方在这里的建议是使用 Kaniko、Img 或 Buildah。我们可以通过把 docker daemon 作为 DaemonSet 或者给想要使用 docker 的 Pod 添加一个 docker daemon 的 sidecar 的方式在任意运行时中使用 DinD 的方案。TKE 也专门为在 containerd 集群中使用 DinD 提供了方案,详见 在containerd中使用DinD。</li></ul><h3 id="containerd-的今生前世"><a href="#containerd-的今生前世" class="headerlink" title="containerd 的今生前世"></a>containerd 的今生前世</h3><p>所以 containerd 到底是个啥?和 docker 又是什么关系?可能有些同学看到博客后会发出这样的疑问,接下来就给同学们讲解下 containerd 和 docker 的渊源。</p><ul><li>docker 与 containerd<br>2016年,docker 把负责容器生命周期的模块拆分出来,并将其捐赠给了社区,也就是现在的 containerd。docker 拆分后结构如下图所示(当然 docker 公司还在 docker 中添加了部分编排的代码)。<br><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006685.png" alt="img"></li></ul><p>在我们调用 docker 命令创建容器后,docker daemon 会通过 Image 模块下载镜像并保存到 Graph Driver 模块中,之后通过 client 调用containerd 创建并运行容器。我们在使用 docker 创建容器时可能需要使用–volume给容器添加持久化存储;还有可能通过–network连接我们用 docker 命令创建的几个容器,当然,这些功能是 docker 中的 Storage 模块和 Networking 模块提供给我们的。但 K8s 提供了更强的卷挂载能力和集群级别的网络能力,在集群中 kubelet 只会使用到 docker 提供的镜像下载和容器管理功能,而编排、网络、存储等功能都不会用到。下图中可以看出当前的模式下各模块的调用链,同时图中被红框标注出的几个模块就是 kubelet 创建 Pod 时所依赖的几个运行时的模块。<br><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006212.png" alt="img"></p><p>containerd 被捐赠给CNCF社区后,社区给其添加了镜像管理模块和 CRI 模块,这样 containerd 不只可以管理容器的生命周期,还可以直接作为 K8s 的运行时使用。于是 containerd 在 2019年2月从 CNCF 社区毕业,正式进入生产环境。下图中能看出以 containerd 作为容器运行时,可以给 kubelet 带来创建 Pod 所需的全部功能,同时还得到了更纯粹的功能模块以及更短的调用链。<br><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205121006769.png" alt="img"><br>从上面的对比可以看出从 containerd 被捐赠给社区开始,就一直以成为简单、稳定且可靠的容器运行时为目标;而 docker 则是希望能成为一个完整的产品。官方文档中也提到了这一点,docker 为了给用户更好的交互和使用体验以及更多的功能,提供了很多开发人员所需要的特性,同时为了给 swarm 做基础,提供了网络和卷的功能。而这些功能其实都是是 K8s 用不上的;containerd 则相反,仅提供了 kubelet 创建 Pod 所需要的基础功能,当然这换来的就是更高的鲁棒性以及更好的性能。在一定程度上讲,即使在 kubelet 1.23 版本之后 docker 提供了 CRI 接口,containerd 仍然是更好的选择。</p><h3 id="仓库相关"><a href="#仓库相关" class="headerlink" title="仓库相关"></a>仓库相关</h3><ol><li>containerd开启deepflow仓库</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nerdctl run -d -e REGISTRY_HTTP_ADDR=0.0.0.0:6000 -v /usr/local/deepflow/registry:/var/lib/registry --restart=always --name registry registry:latest<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 推荐这种</span><br>nerdctl run -d -p 6000:5000 --name deepflow-registry --restart=always --mount <span class="hljs-built_in">type</span>=<span class="hljs-built_in">bind</span>,<span class="hljs-built_in">source</span>=/usr/local/deepflow/registry,target=/var/lib/registry docker.io/library/registry:latest<br></code></pre></td></tr></table></figure><ol start="2"><li>containerd仓库认证,所有节点都要创建</li></ol><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs toml">mkdir /etc/containerd/certs.d/x.x.x.x:6000<br><br>vi /etc/containerd/certs.d/x.x.x.x\:6000/hosts.toml <br><br><br><span class="hljs-attr">server</span> = <span class="hljs-string">"http://x.x.x.x:6000"</span><br><br><span class="hljs-section">[host."http://x.x.x.x:6000"]</span><br> <span class="hljs-attr">capabilities</span> = [<span class="hljs-string">"pull"</span>, <span class="hljs-string">"resolve"</span>, <span class="hljs-string">"push"</span>]<br> <span class="hljs-attr">skip_verify</span> = <span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><ol start="3"><li>重启Containerd</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl daemon-reload && systemctl restart containerd<br>systemctl restart kubelet<br></code></pre></td></tr></table></figure><h1 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a>Docker</h1><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">curl -fsSL https://get.docker.com | bash -s docker --version 23.0 --mirror Aliyun<br><span class="hljs-comment"># 使用阿里云提供的一键安装脚本</span><br></code></pre></td></tr></table></figure><p>安装后配置调整</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs json">cat > /etc/docker/daemon.json <<EOF<br><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"exec-opts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"native.cgroupdriver=systemd"</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"log-driver"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"json-file"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"log-opts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"max-size"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"100m"</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"storage-driver"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"overlay2"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"storage-opts"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-string">"overlay2.override_kernel_check=true"</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"live-restore"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"experimental"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"insecure-registries"</span><span class="hljs-punctuation">:</span><span class="hljs-punctuation">[</span><span class="hljs-string">"registry.rongma.tech"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"docker.nexus.yunshan.net"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"docker-hosted.nexus.yunshan.net"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"10.33.40.166:6000"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"10.33.40.164"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"10.33.40.161:7000"</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"registry-mirrors"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span> <span class="hljs-string">"https://dockerproxy.com"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"https://registry.docker-cn.com"</span><span class="hljs-punctuation">,</span><span class="hljs-string">"https://docker.mirrors.ustc.edu.cn"</span> <span class="hljs-punctuation">]</span><br><span class="hljs-punctuation">}</span><br>EOF<br></code></pre></td></tr></table></figure><h2 id="创建镜像仓库"><a href="#创建镜像仓库" class="headerlink" title="创建镜像仓库"></a>创建镜像仓库</h2><ol><li><p>下载registry镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull registry<br></code></pre></td></tr></table></figure></li><li><p>创建镜像仓库存储目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> -p /opt/registry<br></code></pre></td></tr></table></figure></li><li><p>启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -d -p 5000:5000 -v /opt/registry:/var/lib/registry --restart=always --name registry registry:latest<br></code></pre></td></tr></table></figure></li><li><p>添加仓库信任</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">vim /etc/docker/daemon.json<br><br><span class="hljs-string">"insecure-registries"</span>: [<span class="hljs-string">"10.33.40.142:6000"</span>], <span class="hljs-comment"># 多个仓库的话,中间用逗号隔开</span><br></code></pre></td></tr></table></figure></li><li><p>重载docker</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl daemon-reload && systemctl restart docker<br></code></pre></td></tr></table></figure></li></ol><h2 id="常用命令汇总1(镜像管理、容器运行、停止、进入等)"><a href="#常用命令汇总1(镜像管理、容器运行、停止、进入等)" class="headerlink" title="常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a>常用命令汇总1(镜像管理、容器运行、停止、进入等)</h2><h3 id="镜像管理"><a href="#镜像管理" class="headerlink" title="镜像管理"></a>镜像管理</h3><h4 id="下载镜像"><a href="#下载镜像" class="headerlink" title="下载镜像"></a>下载镜像</h4><p>我们使用 <strong>docker pull</strong> 命令从 <strong>Docker Hub</strong> 上下载指定镜像:</p><p><strong>hello-world</strong> 是 <strong>Docker</strong> 官方提供的一个镜像,通常用来验证 <strong>Docker</strong> 是否安装成。</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">docker pull helle-world</span><br></code></pre></td></tr></table></figure><p>拉取镜像的几个状态:</p><ul><li>Pulling from XXX:解析用户输入的参数,与指定的镜像仓库建立链接</li><li>Already existed:检索本地已有镜像,避免重复下载</li><li>Waiting:该layer正在等待下载</li><li>Pulling fs layer:下载layer的元数据信息</li><li>Downloading,download complete:下载layer</li><li>Extracting:解压缩下载完成的layer</li><li>Pull complete:注册layer</li><li>Digest: sha256:XXX:校验下载的所有layer,并依据所有layer计算得出镜像标识</li><li>Status: Downloaded newer image for XXX:镜像下载完毕</li></ul><h4 id="搜索镜像"><a href="#搜索镜像" class="headerlink" title="搜索镜像"></a>搜索镜像</h4><p>使用 <strong>docker search</strong> 命令可以搜索 <strong>Docker Hub</strong> 中的镜像。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514838.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h4 id="查看已下载的镜像"><a href="#查看已下载的镜像" class="headerlink" title="查看已下载的镜像"></a>查看已下载的镜像</h4><p>使用 <strong>docker images</strong> 命令可以查看所有已下载到本地的镜像。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514564.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h4 id="删除镜像"><a href="#删除镜像" class="headerlink" title="删除镜像"></a>删除镜像</h4><p>使用 <strong>docker rmi</strong> 命令可以删除下载到本地的镜像。</p><p><strong>注意</strong>:删除镜像前要先删除对应的容器(不管是正在运行,还是已经停止的)</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">docker rmi hello-world</span><br></code></pre></td></tr></table></figure><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514560.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h3 id="运行容器"><a href="#运行容器" class="headerlink" title="运行容器"></a>运行容器</h3><h4 id="基本运行"><a href="#基本运行" class="headerlink" title="基本运行"></a>基本运行</h4><p>(1)镜像可以通过 <strong>docker run</strong> 命令运行。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">docker <span class="hljs-built_in">run</span> hello-world<br></code></pre></td></tr></table></figure><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514830.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h4 id="运行时带上参数"><a href="#运行时带上参数" class="headerlink" title="运行时带上参数"></a>运行时带上参数</h4><p>(1)<strong>docker run</strong> 命令支持带上各种参数运行容器。下面以运行一个 <strong>Apache</strong> 服务为例。</p><p><strong>-d</strong>:表示以后台方式启动容器。<br><strong>-p 80:8080</strong>:表示启动后将容器的 <strong>80</strong> 端口映射到 <strong>host</strong> 的 <strong>8080</strong> 端口。</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">docker</span> run -d -p <span class="hljs-number">8080</span>:<span class="hljs-number">80</span> httpd<br></code></pre></td></tr></table></figure><p>(2)默认情况下,容器启动后 <strong>docker</strong> 会自动为容器分配名字。使用 <strong>–name</strong> 可以人工指定容器的名字。</p><figure class="highlight autohotkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs autohotkey">docker run --name ``<span class="hljs-string">"hangge_http_server"</span>` `-d httpd<br></code></pre></td></tr></table></figure><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514722.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h4 id="让容器能够自动重启"><a href="#让容器能够自动重启" class="headerlink" title="让容器能够自动重启"></a>让容器能够自动重启</h4><p>(1)如果希望容器(比如服务类容器)因某种错误而停止运行时,能够自动重启,在启动时设置 <strong>–restart</strong> 就可以到达效果。</p><p><strong>注意</strong>: <strong>–restart</strong> 策略只在启动进程正常退出或发生错误时有效。如果容器时因为执行 <strong>docker stop</strong> 或者 <strong>docker kill</strong> 退出,则不会自动重启。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">docker <span class="hljs-built_in">run</span> <span class="hljs-attribute">--restart</span>=always httpd<br></code></pre></td></tr></table></figure><p>(2)**–restart=always** 表示无论容器因何种原因退出(包括正常退出),都立即重启。如果改成 <strong>–restart=on-failure:3</strong>,则表示如果启动进程退出代码非 <strong>0</strong>,则重启容器,且最多重启 <strong>3</strong> 次。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">docker <span class="hljs-built_in">run</span> <span class="hljs-attribute">--restart</span>=on-failure:3 httpd<br></code></pre></td></tr></table></figure><h4 id="查看正在运行的容器"><a href="#查看正在运行的容器" class="headerlink" title="查看正在运行的容器"></a>查看正在运行的容器</h4><p>(1)使用 <strong>docker ps</strong> 或者 <strong>docker container ls</strong> 命令可以显示哪些容器正在运行(两个命令效果一样):</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514682.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><p>(2)前面两个命令只能查看当前正在运行的容器,使用 <strong>docker ps -a</strong> 或者 <strong>docker container ls -a</strong> 命令则会显示所有状态的容器(包括已经退出的)</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514441.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h3 id="进入容器"><a href="#进入容器" class="headerlink" title="进入容器"></a>进入容器</h3><h4 id="exec命令进入容器"><a href="#exec命令进入容器" class="headerlink" title="exec命令进入容器"></a>exec命令进入容器</h4><p> 容器运行后,我们可能需要进到容器里去做一些工作,比如查看日志、调试、启动其它进程等。有两种方法进入容器,它们分别是 <strong>attach</strong> 和 <strong>exec</strong>:</p><ul><li><strong>attach</strong> 直接进入容器启动命令的终端,不会启动新的进程。</li><li><strong>exec</strong> 则是在容器中打开新的终端,并且可以启动新的进程。</li></ul><p>(1)首先我们启动一个 <strong>Apache Server</strong> 容器。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514537.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><p>(2)我们使用 <strong>docker exec -it</strong> 以交互模式打开 <strong>pseudo-TTY</strong>,执行 <strong>bash</strong>,其结果就是打开了一个 <strong>bash</strong> 终端。</p><figure class="highlight autohotkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs autohotkey">docker ``exec` `-it <span class="hljs-number">0</span>d0553632642 bash<br></code></pre></td></tr></table></figure><p>(3)进入到容器中,容器的 <strong>hostname</strong> 就是其“<strong>短ID</strong>”。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514326.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><p>(4)执行 <strong>exit</strong> 则可退出容器,回到 <strong>docker host</strong>。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514715.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h4 id="run-it"><a href="#run-it" class="headerlink" title="run -it"></a>run -it</h4><p>下面我们使用 <strong>docker run -it</strong> 在 <strong>busybox</strong> 容器启动后就直接进入。进入后通过 <strong>wget</strong> 验证容器访问 <strong>internet</strong> 的能力。</p><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514538.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><h3 id="停止、重启、删除容器"><a href="#停止、重启、删除容器" class="headerlink" title="停止、重启、删除容器"></a>停止、重启、删除容器</h3><h4 id="停止运行的容器"><a href="#停止运行的容器" class="headerlink" title="停止运行的容器"></a>停止运行的容器</h4><p>(1)通过 <strong>docker stop</strong> 可以停止运行的容器,下面根据容器名字来停止。</p><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs arduino">docker stop hangge_http_server<br></code></pre></td></tr></table></figure><p>(2)如果想要快速停止容器,可以使用 <strong>docker kill</strong> 命令。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">kill</span> hangge_http_server<br></code></pre></td></tr></table></figure><h4 id="启动停止的容器"><a href="#启动停止的容器" class="headerlink" title="启动停止的容器"></a>启动停止的容器</h4><p>使用 <strong>docker start</strong> 可以重新启动处于停止状态的容器,并且保留容器的第一次启动时的所有参数。</p><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs crmsh">docker <span class="hljs-literal">start</span> hangge_http_server<br></code></pre></td></tr></table></figure><h4 id="重启容器"><a href="#重启容器" class="headerlink" title="重启容器"></a>重启容器</h4><p><strong>docker restart</strong> 可以重启容器,其作用就是依次执行 <strong>docker stop</strong> 和 <strong>docker start</strong>。</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">docker restart hangge_http_server</span><br></code></pre></td></tr></table></figure><h4 id="暂停-恢复容器"><a href="#暂停-恢复容器" class="headerlink" title="暂停/恢复容器"></a>暂停/恢复容器</h4><p>(1)如果只是希望容器暂停工作一段时间,比如对容器的文件系统大打个快照,或者 <strong>docker host</strong> 需要使用 <strong>CPU</strong>,这是可以执行 <strong>docker pause</strong> 将其暂停。</p><figure class="highlight autohotkey"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs autohotkey">docker <span class="hljs-keyword">pause</span> hangge_http_server<br></code></pre></td></tr></table></figure><p><a href="https://www.hangge.com/blog/cache/detail_2402.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051514536.png" alt="原文:Docker - 常用命令汇总1(镜像管理、容器运行、停止、进入等)"></a></p><p>(2)处于暂停状态的容器不会占用 <strong>CPU</strong>,直到通过 <strong>docker unpause</strong> 恢复运行。</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">docker unpause hangge_http_server</span><br></code></pre></td></tr></table></figure><h4 id="删除容器"><a href="#删除容器" class="headerlink" title="删除容器"></a>删除容器</h4><p>(1)使用 <strong>docker</strong> 一段时间后,<strong>host</strong> 上可能会有大量已经退出了的容器。我们可以使用 <strong>docker rm</strong> 命令删除。下面通过容器的短 <strong>id</strong> 删除:</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">docker</span> rm <span class="hljs-number">9</span>d3d9622aafa<br></code></pre></td></tr></table></figure><p>(2)<strong>docker rm</strong> 一次可以指定多个容器删除。</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">docker</span> rm <span class="hljs-number">9</span>d3d9622aafa e12cc2a63fd3<br></code></pre></td></tr></table></figure><p>(3)如果希望批量删除所有已经退出的容器,可以执行如下命令。</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs powershell">docker <span class="hljs-built_in">rm</span> <span class="hljs-literal">-v</span> <span class="hljs-variable">$</span>(docker <span class="hljs-built_in">ps</span> <span class="hljs-literal">-aq</span> <span class="hljs-operator">-f</span> status=exited)<br></code></pre></td></tr></table></figure><h3 id="汇总"><a href="#汇总" class="headerlink" title="汇总"></a>汇总</h3><h4 id="docker基本命令"><a href="#docker基本命令" class="headerlink" title="docker基本命令"></a>docker基本命令</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker version 查看docker版本<br>docker info 查看docker详细信息<br>docker --<span class="hljs-built_in">help</span> 查看docker命令<br></code></pre></td></tr></table></figure><h4 id="镜像命令"><a href="#镜像命令" class="headerlink" title="镜像命令"></a>镜像命令</h4><p>Usage: docker [OPTIONS] COMMAND</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@localhost ~]# docker images <span class="hljs-comment">#列出本地镜像</span><br>REPOSITORY TAG IMAGE ID CREATED SIZE<br>nginx add 206e386c25f3 8 hours ago 134MB<br>nginx user e5abc3364a3c 8 hours ago 134MB<br><none> <none> 7661e32369e1 8 hours ago 134MB<br>golang latest 8735189b1527 25 hours ago 941MB<br>nginx index dd34e67e3371 44 hours ago 133MB<br>nginx latest dd34e67e3371 44 hours ago 133MB<br><br>PEPOSITORY:镜像的仓库源<br>TAG:镜像的标签<br>IMAGE ID:镜像ID<br>CREATED:镜像创建时间<br>SIZE:镜像大小<br>同一个仓库源可以有多个TAG,表示这个仓库源的不同版本,我们使用REPOSITORY:TAG来定义不同的镜像。如果不指定一个镜像的版本标签,例如只使用tomcat,docker将默认使用tomcat:latest镜像<br><br>docker images -a 列出本地所有的镜像<br>docker images -p 只显示镜像ID<br>docker images --digests 显示镜像的摘要信息<br>docker images --no-trunc显示完整的镜像信息<br><br>---------------------------------------------------------------------------------<br><br>[root@localhost ~]# docker search tomcat <span class="hljs-comment">#从docker镜像仓库搜寻镜像</span><br>NAME DESCRIPTION STARS OFFICIAL AUTOMATED<br>tomcat Apache Tomcat is an open <span class="hljs-built_in">source</span> implementati… 3097 [OK] <br>tomee Apache TomEE is an all-Apache Java EE certif… 91 [OK] <br>dordoka/tomcat Ubuntu 14.04, Oracle JDK 8 and Tomcat 8 base… 57 [OK]<br><br>STARS:关注度<br>docker search -s 30 tomcat 从Docker Hub上查找关注度大于30的tomcat镜像<br>docker pull tomcat 从Docker Hub上下载tomcat镜像。等价于:docker pull tomcat:latest<br>docker commit -m <span class="hljs-string">"message"</span> -a <span class="hljs-string">"auditor"</span> 容器ID 要创建的目标镜像名称:[标签名]提交容器使之成为一个新的镜像。<br>如:docker commit -m <span class="hljs-string">"新的tomcat"</span> -a <span class="hljs-string">"lizq"</span> f9e29e8455a5 mytomcat:1.2<br>docker rmi hello-world 从Docker中删除hello-world镜像<br>docker rmi -f hello-world 从Docker中强制删除hello-world镜像<br>docker rmi -f hello-world nginx 从Docker中强制删除hello-world镜像和nginx镜像<br>docker rmi -f $(docker images -p) 通过docker images -p查询到的镜像ID来删除所有镜像<br></code></pre></td></tr></table></figure><h4 id="容器命令"><a href="#容器命令" class="headerlink" title="容器命令"></a>容器命令</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run [OPTIONS] IMAGE根据镜像新建并启动容器。IMAGE是镜像ID或镜像名称<br>OPTIONS说明:<br> --name=“容器新名字”:为容器指定一个名称<br> -d:后台运行容器,并返回容器ID,也即启动守护式容器<br> -i:以交互模式运行容器,通常与-t同时使用<br> -t:为容器重新分配一个伪输入终端,通常与-i同时使用<br> -P:随机端口映射<br> -p:指定端口映射,有以下四种格式:<br> ip:hostPort:containerPort<br> ip::containerPort<br> hostPort:containerPort<br> containerPort<br> <br>----------------------------------------------<br>docker ps列出当前所有正在运行的容器<br>docker ps -a列出所有的容器<br>docker ps -l列出最近创建的容器<br>docker ps -n 3列出最近创建的3个容器<br>docker ps -q只显示容器ID<br>docker ps --no-trunc显示当前所有正在运行的容器完整信息<br><span class="hljs-built_in">exit</span>退出并停止容器<br>Ctrl+p+q只退出容器,不停止容器<br>docker start 容器ID或容器名称启动容器<br>docker restart 容器ID或容器名称重新启动容器<br>docker stop容器ID或容器名称停止容器<br>docker <span class="hljs-built_in">kill</span> 容器ID或容器名称强制停止容器<br>docker <span class="hljs-built_in">rm</span> 容器ID或容器名称删除容器<br>docker <span class="hljs-built_in">rm</span> -f 容器ID或容器名称强制删除容器<br>docker <span class="hljs-built_in">rm</span> -f $(docker ps -a -q)删除多个容器<br>docker logs -f -t --since --<span class="hljs-built_in">tail</span> 容器ID或容器名称查看容器日志<br>如:docker logs -f -t --since=”2018-09-10” --<span class="hljs-built_in">tail</span>=10 f9e29e8455a5<br> -f : 查看实时日志<br> -t : 查看日志产生的日期<br> --since : 此参数指定了输出日志开始日期,即只输出指定日期之后的日志<br> --<span class="hljs-built_in">tail</span>=10 : 查看最后的10条日志<br>docker top 容器ID或容器名称查看容器内运行的进程<br>docker inspect 容器ID或容器名称查看容器内部细节<br>docker attach 容器ID进到容器内<br>docker <span class="hljs-built_in">exec</span> 容器ID进到容器内<br>docker <span class="hljs-built_in">cp</span> 容器ID:容器内的文件路径 宿主机路径从容器内拷贝文件到宿主机.<br></code></pre></td></tr></table></figure><h2 id="Docker容器存储"><a href="#Docker容器存储" class="headerlink" title="Docker容器存储"></a>Docker容器存储</h2><p> 对于有些容器,我们可能会有持续化数据的需求,也就是容器启动时需要加载已有的数据,容器销毁时希望保留产生的数据,也就是说这类容器是有状态的。</p><p> 这个就需要用到 <strong>Docker</strong> 的 <strong>Data Volume</strong> 存储机制。<strong>Data Volume</strong> 本质上是 <strong>Docker Host</strong> 文件系统中的目录或文件,能够直接被 <strong>mount</strong> 到容器的文件系统。</p><p> 在具体的使用上,<strong>docker</strong> 提供了两张类型的 <strong>volume</strong>:<strong>bind mount</strong> 和 <strong>docker managed volume</strong>。下面分别进行介绍。</p><h3 id="bind-mount"><a href="#bind-mount" class="headerlink" title="bind mount"></a>bind mount</h3><h4 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h4><p>(1)下面在容器启动时通过 <strong>-v</strong> 参数将 <strong>docker host</strong> 上的 <strong>$HOME/htdocs</strong> 目录 <strong>mount</strong>到 <strong>httpd</strong> 容器里。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">run</span><span class="language-bash"> -d -v ~/htdocs:/usr/local/apache2/htdocs httpd</span><br></code></pre></td></tr></table></figure><p>(2)这里的 <strong>/usr/local/apache2/htdocs</strong> 就是 <strong>Apache Server</strong> 存放静态文件的地方。<strong>mount</strong> 后,容器中 <strong>/usr/local/apache2/htdocs</strong> 里原有数据会被隐藏起来,取而代之代之的是 <strong>host $HOME/htdocs/</strong> 中的数据。</p><p><strong>注意</strong>:当我们 <strong>mount</strong> 一个目录时,如果更改宿主机目录里的内容,容器内对应的内容也会同步更新,不需要重启容器。</p><h4 id="指定数据的读写权限"><a href="#指定数据的读写权限" class="headerlink" title="指定数据的读写权限"></a>指定数据的读写权限</h4><p>默认情况下 <strong>mount</strong> 的数据是可读可写的。我们可以添加 <strong>ro</strong> 参数设置成只读权限,此时:</p><ul><li>在容器中无法对 <strong>bind mount</strong> 数据进行修改。 </li><li>只有 <strong>host</strong> 有权修改数据。</li></ul><p><a href="https://www.hangge.com/blog/cache/detail_2403.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051515079.png" alt="原文:Docker - 容器存储详解1(使用Data Volume实现数据持久化)"></a></p><h4 id="bind-mount-单个文件"><a href="#bind-mount-单个文件" class="headerlink" title="bind mount 单个文件"></a>bind mount 单个文件</h4><p> 如果只需要向容器添加文件,不希望覆盖整个目录,可以使用 <strong>bind mount</strong> 单个文件。下面样例,我们将一个 <strong>html</strong> 文件添加到 <strong>apache</strong> 中,同时也保留了容器原有的数据后。</p><p><strong>注意</strong>:如果我们 <strong>mount</strong> 的是单个文件的话,不同于 <strong>mount</strong> 整个目录,运行后如果宿主机的这个文件进行了修改,容器内对应的文件内容是不会同步变化的,必须重启容器才会更新。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">run</span><span class="language-bash"> -d -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd</span><br></code></pre></td></tr></table></figure><h3 id="docker-managed-volume"><a href="#docker-managed-volume" class="headerlink" title="docker managed volume"></a>docker managed volume</h3><h4 id="基本用法-1"><a href="#基本用法-1" class="headerlink" title="基本用法"></a>基本用法</h4><p>(1)<strong>docker managed volume</strong> 和 <strong>bind mount</strong> 在使用上最大的区别是不需要指定 <strong>mount</strong> 源,指明 <strong>mount point</strong> 就好。<br>(2)同样以 <strong>httpd</strong> 容器为例。我们通过 <strong>-v</strong> 告诉它需要一个 <strong>data volume</strong>,并将其 <strong>mount</strong> 到 <strong>/usr/local/apache2/htdocs</strong>。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">run</span><span class="language-bash"> -d -v /usr/local/apache2/htdocs httpd</span><br></code></pre></td></tr></table></figure><p>(3)上面执行后,<strong>docker</strong> 就会自动在 <strong>host</strong> 的 <strong>/var/lib/docker/volumes</strong> 下生成一个目录,这个目录就是 <strong>mount</strong> 源。同时还会将容器里中 <strong>/usr/local/apache2/htdocs</strong> 数据复制到 <strong>mount</strong> 源中。</p><h4 id="data-volume具体位置"><a href="#data-volume具体位置" class="headerlink" title="data volume具体位置"></a>data volume具体位置</h4><p>(1)当容器申请 <strong>mount docker managed volume</strong> 时,<strong>docker</strong> 会在 <strong>/var/lib/docker/volumes</strong> 下生成一个目录作为 <strong>mount</strong> 源。要找到它我们先执行 <strong>docker inspect</strong> 查看容器配置信息:</p><p><a href="https://www.hangge.com/blog/cache/detail_2403.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051515087.png" alt="原文:Docker - 容器存储详解1(使用Data Volume实现数据持久化)"></a></p><p>(2)在 <strong>Mounts</strong> 这部分的信息中会显示容器当前所使用的所有 <strong>data volume</strong>,包括 <strong>bind mount</strong> 和 <strong>docker managed volume</strong>。</p><p><a href="https://www.hangge.com/blog/cache/detail_2403.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051515938.png" alt="原文:Docker - 容器存储详解1(使用Data Volume实现数据持久化)"></a></p><p>(3)我们进这个文件夹可以看到,容器里中 <strong>/usr/local/apache2/htdocs</strong> 数据确实已经复制到这个 <strong>mount</strong> 源中。</p><p><a href="https://www.hangge.com/blog/cache/detail_2403.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051515912.png" alt="原文:Docker - 容器存储详解1(使用Data Volume实现数据持久化)"></a></p><h3 id="附:bind-mount-与-docker-managed-volume-的区别"><a href="#附:bind-mount-与-docker-managed-volume-的区别" class="headerlink" title="附:bind mount 与 docker managed volume 的区别"></a>附:bind mount 与 docker managed volume 的区别</h3><p>这两种 <strong>data volume</strong> 实际上都是使用 <strong>host</strong> 文件系统的中的某个路径作为 <strong>mount</strong> 源。它们不同之处在于:</p><table><thead><tr><th><strong>不同点</strong></th><th><strong>bind mount</strong></th><th><strong>docker managed volume</strong></th></tr></thead><tbody><tr><td><strong>volume 位置</strong></td><td>可任意指定</td><td><strong>/var/lib/docker/volumes/…</strong></td></tr><tr><td><strong>对已有mount point 影响</strong></td><td>隐藏并替换为 <strong>volume</strong></td><td>原有数据复制到 <strong>volume</strong></td></tr><tr><td><strong>是否支持单个文件</strong></td><td>支持</td><td>不支持,只能是目录</td></tr><tr><td><strong>权限控制</strong></td><td>可设置为只读,默认为读写权限</td><td>无控制,均为读写权限</td></tr><tr><td><strong>移植性</strong></td><td>移植性弱,与 <strong>host path</strong> 绑定</td><td>移植性强,无需指定 <strong>host</strong> 目录</td></tr></tbody></table><p> 由于 <strong>docker</strong> 不会销毁 <strong>bind mount</strong>,删除数据的工作只能由 <strong>host</strong> 负责。下面介绍如何删除 <strong>docker managed volume</strong>。</p><h3 id="销毁-Data-Volume"><a href="#销毁-Data-Volume" class="headerlink" title="销毁 Data Volume"></a>销毁 Data Volume</h3><h4 id="删除数据的基本方法"><a href="#删除数据的基本方法" class="headerlink" title="删除数据的基本方法"></a>删除数据的基本方法</h4><p>对于 <strong>docker managed volume</strong>,在执行 <strong>docker rm</strong> 删除容器时可带上 <strong>-v</strong> 参数,<strong>docker</strong> 会将容器使用到的 <strong>volume</strong> 删除。</p><p>但其前提是没有其它容器 <strong>mount</strong> 该 <strong>volume</strong>,目的是保护数据。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">rm</span> -v web1<br></code></pre></td></tr></table></figure><h4 id="删除孤儿-volume"><a href="#删除孤儿-volume" class="headerlink" title="删除孤儿 volume"></a>删除孤儿 volume</h4><p>(1)容器使用的 <strong>docker managed volume</strong> 可以通过 <strong>docker volume ls</strong> 命令查看(无论是否是孤儿 <strong>volume</strong> 都会显示出来):</p><p><a href="https://www.hangge.com/blog/cache/detail_2405.html#"><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051515937.png" alt="原文:Docker - 容器存储详解3(销毁Data Volume)"></a></p><p>(2)如果没有使用 <strong>-v</strong> 删除容器,而使得 <strong>volume</strong> 遗留下来的话,可以使用 <strong>docker volume rm</strong> 命令删除:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">volume</span><span class="language-bash"> <span class="hljs-built_in">rm</span> bc399624cbb9dbc3837600b02f83ae03ce8360a078f68f8e62d9946b9446e9db</span><br></code></pre></td></tr></table></figure><p>(3)当然我们也可以使用下面命令批量删除所有的孤儿 <strong>volume</strong>:</p><p>虽然该命令是删除所有 <strong>volume</strong>,但由于数据保护,目前有容器使用的 <strong>volume</strong> 是不会被删除的。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">volume</span><span class="language-bash"> <span class="hljs-built_in">rm</span> $(docker volume <span class="hljs-built_in">ls</span> -q)</span><br></code></pre></td></tr></table></figure><h2 id="Docker网络"><a href="#Docker网络" class="headerlink" title="Docker网络"></a>Docker网络</h2><p>docker使用Linux桥,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据Docker网桥的网段分配一个容器一个IP地址,成为container-IP,同时docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器都接入一个网桥,这样容器就能通过容器的container-IP进行通信。</p><p>docker网桥是宿主机虚拟出来的,并不是真实存在的网卡设备,外部网络是无法寻址的,这也就意为着外部网络无法直接通过container-IP访问容器。如果容器希望外部主机访问到,可以通过映射容器端口到宿主机的某一个端口(端口映射),即docker run创建容器-p或者-P参数启动,访问容器的时候就只直接访问**[宿主机]:[容器映射到宿主机的端口]**</p><table><thead><tr><th><strong>Docker网络模式</strong></th><th><strong>配置</strong></th><th><strong>说明</strong></th></tr></thead><tbody><tr><td>host模式</td><td>–net=host</td><td>容器和宿主机共享Network namespace。</td></tr><tr><td>container模式</td><td>–net=container:NAME_or_ID</td><td>容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。</td></tr><tr><td>none模式</td><td>–net=none</td><td>容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。</td></tr><tr><td>bridge模式</td><td>–net=bridge</td><td>(默认为该模式)</td></tr></tbody></table><h3 id="host模式"><a href="#host模式" class="headerlink" title="host模式"></a>host模式</h3><p>如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。</p><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051517410.png" alt="image-20220322143256602"></p><h3 id="Container模式"><a href="#Container模式" class="headerlink" title="Container模式"></a>Container模式</h3><p>这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。</p><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051517457.png" alt="image-20220322143313031"></p><h3 id="Node模式"><a href="#Node模式" class="headerlink" title="Node模式"></a>Node模式</h3><p>使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。</p><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051517392.png" alt="image-20220322143319554"></p><h3 id="bridge模式"><a href="#bridge模式" class="headerlink" title="bridge模式"></a>bridge模式</h3><p>当docker进程启动时,会在主机上创建一个docker0的虚拟网桥,此主机上启动的docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,。</p><p>从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。</p><p>bridge模式是docker的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。</p><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202209051517369.png" alt="image-20220322143325150"></p><h2 id="Dockerfile-定制镜像"><a href="#Dockerfile-定制镜像" class="headerlink" title="Dockerfile 定制镜像"></a>Dockerfile 定制镜像</h2><h3 id="Dockerfile-定制镜像-1"><a href="#Dockerfile-定制镜像-1" class="headerlink" title="Dockerfile 定制镜像"></a>Dockerfile 定制镜像</h3><p>镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 <code>Dockerfile</code>。</p><p><code>Dockerfile</code> 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。</p><p>以 <code>nginx</code> 镜像为例,这次我们使用 <code>Dockerfile</code> 来定制。</p><p>在一个空白目录中,建立一个文本文件,并命名为 <code>Dockerfile</code>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs shell"><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">mkdir</span> mynginx</span><br><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">cd</span> mynginx</span><br><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">touch</span> Dockerfile</span><br></code></pre></td></tr></table></figure><p>其内容为:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> nginx<br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'<h1>Hello, Docker!</h1>'</span> > /usr/share/nginx/html/index.html</span><br></code></pre></td></tr></table></figure><p>这个 <code>Dockerfile</code> 很简单,一共就两行。涉及到了两条指令,<code>FROM</code> 和 <code>RUN</code>。</p><h3 id="FROM-指定基础镜像"><a href="#FROM-指定基础镜像" class="headerlink" title="FROM 指定基础镜像"></a>FROM 指定基础镜像</h3><p>所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 <code>nginx</code> 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 <code>FROM</code> 就是指定<strong>基础镜像</strong>,因此一个 <code>Dockerfile</code> 中 <code>FROM</code>是必备的指令,并且必须是第一条指令。</p><p>在 <code>Docker Store</code> 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 <code>nginx</code>、<code>redis</code>、<code>mongo</code>、<code>mysql</code>、<code>httpd</code>、<code>php</code>、<code>tomcat</code> 等;也有一些方便开发、构建、运行各种语言应用的镜像,如<code>node</code>、<code>openjdk</code>、<code>python</code>、<code>ruby</code>、<code>golang</code>等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。</p><p>如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如<code>ubuntu</code>、<code>debian</code>、<code>centos</code>、<code>fedora</code>、<code>alpine</code> 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。</p><p>除了选择现有镜像为基础镜像外,<code>Docker</code> 还存在一个特殊的镜像,名为 <code>scratch</code>。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。</p><figure class="highlight node-repl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs node-repl">FROM scratch<br><span class="hljs-meta prompt_">...</span><br></code></pre></td></tr></table></figure><blockquote><p>如果你以 <code>scratch</code> 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。</p></blockquote><p>不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如<code>swarm</code>、<code>coreos/etcd</code>。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 <code>FROM scratch</code> 会让镜像体积更加小巧。使用 Go 语言开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 <code>Go</code> 是特别适合容器微服务架构的语言的原因之一。</p><h3 id="RUN-执行命令"><a href="#RUN-执行命令" class="headerlink" title="RUN 执行命令"></a>RUN 执行命令</h3><p><code>RUN</code> 指令是用来执行命令行命令的。由于命令行的强大能力,<code>RUN</code> 指令在定制镜像时是最常用的指令之一。其格式有两种:</p><ul><li><em>shell</em> 格式:<code>RUN <命令></code>,就像直接在命令行中输入的命令一样。刚才写的 <code>Dockerfile</code> 中的 <code>RUN</code> 指令就是这种格式。</li></ul><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'<h1>Hello, Docker!</h1>'</span> > /usr/share/nginx/html/index.html</span><br></code></pre></td></tr></table></figure><ul><li><em>exec</em> 格式:<code>RUN ["可执行文件", "参数1", "参数2"]</code>,这更像是函数调用中的格式。</li></ul><p>既然 <code>RUN</code> 就像 <code>Shell</code> 脚本一样可以执行命令,那么我们是否就可以像 <code>Shell</code> 脚本一样把每个命令对应一个 <code>RUN</code> 呢?比如这样:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> debian:jessie<br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get install -y gcc libc6-dev make</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> wget -O redis.tar.gz <span class="hljs-string">"http://download.redis.io/releases/redis-3.2.5.tar.gz"</span></span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">mkdir</span> -p /usr/src/redis</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> make -C /usr/src/redis</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> make -C /usr/src/redis install</span><br></code></pre></td></tr></table></figure><p>之前说过,<code>Dockerfile</code> 中每一个指令都会建立一层,<code>RUN</code> 也不例外。每一个 <code>RUN</code> 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,<code>commit</code> 这一层的修改,构成新的镜像。</p><p>而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。这是很多初学 <code>Docker</code> 的人常犯的一个错误。</p><p><em><code>Union FS</code> 是有最大层数限制的,比如 <code>AUFS</code>,曾经是最大不能超过 42 层,现在是不能超过 127 层。</em></p><p>上面的 <code>Dockerfile</code> 正确的写法应该是这样:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> debian:jessie<br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> buildDeps=<span class="hljs-string">'gcc libc6-dev make'</span> \</span><br><span class="language-bash"> && apt-get update \</span><br><span class="language-bash"> && apt-get install -y <span class="hljs-variable">$buildDeps</span> \</span><br><span class="language-bash"> && wget -O redis.tar.gz <span class="hljs-string">"http://download.redis.io/releases/redis-3.2.5.tar.gz"</span> \</span><br><span class="language-bash"> && <span class="hljs-built_in">mkdir</span> -p /usr/src/redis \</span><br><span class="language-bash"> && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \</span><br><span class="language-bash"> && make -C /usr/src/redis \</span><br><span class="language-bash"> && make -C /usr/src/redis install \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/* \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> redis.tar.gz \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> -r /usr/src/redis \</span><br><span class="language-bash"> && apt-get purge -y --auto-remove <span class="hljs-variable">$buildDeps</span></span><br></code></pre></td></tr></table></figure><p>首先,之前所有的命令只有一个目的,就是编译、安装 <code>Redis</code> 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 <code>RUN</code> 对一一对应不同的命令,而是仅仅使用一个 <code>RUN</code> 指令,并使用 <code>&&</code> 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 <code>Dockerfile</code> 的时候,要经常提醒自己,这并不是在写 <code>Shell</code> 脚本,而是在定义每一层该如何构建。</p><p>并且,这里为了格式化还进行了换行。<code>Dockerfile</code> 支持 Shell 类的行尾添加 <code>\</code> 的命令换行方式,以及行首 <code>#</code> 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。</p><p>此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了 <code>apt</code> 缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。</p><p>很多人初学 <code>Docker</code> 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。</p><h3 id="构建镜像"><a href="#构建镜像" class="headerlink" title="构建镜像"></a>构建镜像</h3><p>再回到之前定制的 <code>Nginx</code> 镜像的 <code>Dockerfile</code> 来。现在我们明白了这个 <code>Dockerfile</code> 的内容,那么让我们来构建这个镜像吧。</p><p>在 <code>Dockerfile</code> 文件所在目录执行:</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs pgsql">$ docker build -t nginx:v3 .<br>Sending build context <span class="hljs-keyword">to</span> Docker daemon <span class="hljs-number">2.048</span> kB<br>Step <span class="hljs-number">1</span> : <span class="hljs-keyword">FROM</span> nginx<br> <span class="hljs-comment">---> e43d811ce2f4</span><br>Step <span class="hljs-number">2</span> : RUN echo <span class="hljs-string">'<h1>Hello, Docker!</h1>'</span> > /usr/<span class="hljs-keyword">share</span>/nginx/html/<span class="hljs-keyword">index</span>.html<br> <span class="hljs-comment">---> Running in 9cdc27646c7b</span><br> <span class="hljs-comment">---> 44aa4490ce2c</span><br>Removing intermediate container <span class="hljs-number">9</span>cdc27646c7b<br>Successfully built <span class="hljs-number">44</span>aa4490ce2c<br></code></pre></td></tr></table></figure><p>从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 <code>Step 2</code>中,如同我们之前所说的那样,<code>RUN</code> 指令启动了一个容器 <code>9cdc27646c7b</code>,执行了所要求的命令,并最后提交了这一层 <code>44aa4490ce2c</code>,随后删除了所用到的这个容器 <code>9cdc27646c7b</code>。</p><p>这里我们使用了 <code>docker build</code> 命令进行镜像构建。其格式为:</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs livescript">docker build [选项] <上下文路径<span class="hljs-regexp">/URL/</span>-><br></code></pre></td></tr></table></figure><p>在这里我们指定了最终镜像的名称 <code>-t nginx:v3</code>,构建成功后,我们可以像之前运行 <code>nginx:v2</code> 那样来运行这个镜像,其结果会和 <code>nginx:v2</code>一样。</p><h3 id="镜像构建上下文(Context)"><a href="#镜像构建上下文(Context)" class="headerlink" title="镜像构建上下文(Context)"></a>镜像构建上下文(Context)</h3><p>如果注意,会看到 <code>docker build</code> 命令最后有一个 <code>.</code>,<code>.</code> 表示当前目录,而 <code>Dockerfile</code> 就在当前目录,因此不少初学者以为这个路径是在指定 <code>Dockerfile</code> 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定<strong>上下文路径</strong>。那么什么是上下文呢?</p><p>首先我们要理解 <code>docker build</code> 的工作原理。<code>Docker</code> 在运行时分为 <code>Docker</code> 引擎(也就是服务端守护进程)和客户端工具。<code>Docker</code> 的引擎提供了一组 REST API,被称为 <code>Docker Remote API</code>,而如 <code>docker</code> 命令这样的客户端工具,则是通过这组 <code>API</code> 与 <code>Docker</code> 引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 <code>docker</code> 功能,但实际上,一切都是使用的远程调用形式在服务端(<code>Docker</code> 引擎)完成。也因为这种 <code>C/S</code> 设计,让我们操作远程服务器的 <code>Docker</code> 引擎变得轻而易举。</p><p>当我们进行镜像构建的时候,并非所有定制都会通过 <code>RUN</code> 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 <code>COPY</code> 指令、<code>ADD</code> 指令等。而 <code>docker build</code> 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 <code>Docker</code> 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?</p><p>这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,<code>docker build</code> 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 <code>Docker</code> 引擎。这样 <code>Docker</code> 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。</p><p>如果在 <code>Dockerfile</code> 中这么写:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">COPY</span><span class="language-bash"> ./package.json /app/</span><br></code></pre></td></tr></table></figure><p>这并不是要复制执行 <code>docker build</code> 命令所在的目录下的 <code>package.json</code>,也不是复制 <code>Dockerfile</code> 所在目录下的 <code>package.json</code>,而是复制 <strong>上下文(context)</strong> 目录下的 <code>package.json</code>。</p><p>因此,<code>COPY</code> 这类指令中的源文件的路径都是<em>相对路径</em>。这也是初学者经常会问的为什么 <code>COPY ../package.json /app</code> 或者 <code>COPY /opt/xxxx /app</code> 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。</p><p>现在就可以理解刚才的命令 <code>docker build -t nginx:v3 .</code> 中的这个 <code>.</code>,实际上是在指定上下文的目录,<code>docker build</code> 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。</p><p>如果观察 <code>docker build</code> 输出,我们其实已经看到了这个发送上下文的过程:</p><figure class="highlight erlang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs erlang"><span class="hljs-string">$ </span>docker build -t nginx:v3 .<br>Sending build context to Docker daemon <span class="hljs-number">2.048</span> kB<br>...<br></code></pre></td></tr></table></figure><p>理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 <code>COPY /opt/xxxx /app</code> 不工作后,于是干脆将 <code>Dockerfile</code> 放到了硬盘根目录去构建,结果发现 <code>docker build</code> 执行后,在发送一个几十 <code>GB</code> 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 <code>docker build</code> 打包整个硬盘,这显然是使用错误。</p><p>一般来说,应该会将 <code>Dockerfile</code> 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 <code>.gitignore</code> 一样的语法写一个 <code>.dockerignore</code>,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。</p><p>那么为什么会有人误以为 <code>.</code> 是指定 <code>Dockerfile</code> 所在目录呢?这是因为在默认情况下,如果不额外指定 <code>Dockerfile</code> 的话,会将上下文目录下的名为 <code>Dockerfile</code> 的文件作为 Dockerfile。</p><p>这只是默认行为,实际上 <code>Dockerfile</code> 的文件名并不要求必须为 <code>Dockerfile</code>,而且并不要求必须位于上下文目录中,比如可以用 <code>-f ../Dockerfile.php</code> 参数指定某个文件作为 <code>Dockerfile</code>。</p><p>当然,一般大家习惯性的会使用默认的文件名 <code>Dockerfile</code>,以及会将其置于镜像构建上下文目录中。</p><h3 id="其他-docker-build-的用法"><a href="#其他-docker-build-的用法" class="headerlink" title="其他 docker build 的用法"></a>其他 docker build 的用法</h3><h4 id="直接用-Git-repo-进行构建"><a href="#直接用-Git-repo-进行构建" class="headerlink" title="直接用 Git repo 进行构建"></a>直接用 Git repo 进行构建</h4><p><code>docker build</code> 还支持从 <code>URL</code> 构建,比如可以直接从 <code>Git repo</code> 中构建:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs vim">$ docker build https://github.<span class="hljs-keyword">com</span>/twang2218/gitlab-<span class="hljs-keyword">ce</span>-zh.git#:<span class="hljs-number">8.14</span><br>docker build https://github.<span class="hljs-keyword">com</span>/twang2218/gitlab-<span class="hljs-keyword">ce</span>-zh.git\#:<span class="hljs-number">8.14</span><br>Sending build context <span class="hljs-keyword">to</span> Docker daemon <span class="hljs-number">2.048</span> kB<br>Step <span class="hljs-number">1</span> : FROM gitlab/gitlab-<span class="hljs-keyword">ce</span>:<span class="hljs-number">8.14</span>.<span class="hljs-number">0</span>-<span class="hljs-keyword">ce</span>.<span class="hljs-number">0</span><br><span class="hljs-number">8.14</span>.<span class="hljs-number">0</span>-<span class="hljs-keyword">ce</span>.<span class="hljs-number">0</span>: Pulling from gitlab/gitlab-<span class="hljs-keyword">ce</span><br>aed15891ba52: Already <span class="hljs-built_in">exists</span><br><span class="hljs-number">773</span>ae8583d14: Already <span class="hljs-built_in">exists</span><br>...<br></code></pre></td></tr></table></figure><p>这行命令指定了构建所需的 <code>Git repo</code>,并且指定默认的 <code>master</code> 分支,构建目录为 <code>/8.14/</code>,然后 Docker 就会自己去 <code>git clone</code> 这个项目、切换到指定分支、并进入到指定目录后开始构建。</p><h4 id="用给定的-tar-压缩包构建"><a href="#用给定的-tar-压缩包构建" class="headerlink" title="用给定的 tar 压缩包构建"></a>用给定的 tar 压缩包构建</h4><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs crystal"><span class="hljs-variable">$ </span>docker build <span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/server/context</span>.tar.gz<br></code></pre></td></tr></table></figure><p>如果所给出的 URL 不是个 <code>Git repo</code>,而是个 <code>tar</code> 压缩包,那么 <code>Docker</code> 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。</p><h4 id="从标准输入中读取-Dockerfile-进行构建"><a href="#从标准输入中读取-Dockerfile-进行构建" class="headerlink" title="从标准输入中读取 Dockerfile 进行构建"></a>从标准输入中读取 Dockerfile 进行构建</h4><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm">docker <span class="hljs-keyword">build </span>- < Dockerfile<br></code></pre></td></tr></table></figure><p>或</p><figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs 1c">cat Dockerfile <span class="hljs-string">| docker build -</span><br></code></pre></td></tr></table></figure><p>如果标准输入传入的是文本文件,则将其视为 <code>Dockerfile</code>,并开始构建。这种形式由于直接从标准输入中读取 <code>Dockerfile</code> 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 <code>COPY</code> 进镜像之类的事情。</p><h4 id="从标准输入中读取上下文压缩包进行构建"><a href="#从标准输入中读取上下文压缩包进行构建" class="headerlink" title="从标准输入中读取上下文压缩包进行构建"></a>从标准输入中读取上下文压缩包进行构建</h4><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm">$ docker <span class="hljs-keyword">build </span>- < <span class="hljs-built_in">context</span>.tar.gz<br></code></pre></td></tr></table></figure><p>如果发现标准输入的文件格式是 <code>gzip</code>、<code>bzip2</code> 以及 <code>xz</code> 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。</p><h2 id="Dockerfile-指令"><a href="#Dockerfile-指令" class="headerlink" title="Dockerfile 指令"></a>Dockerfile 指令</h2><p>我们已经介绍了 <code>FROM</code>,<code>RUN</code>,还提及了 <code>COPY</code>, <code>ADD</code>,其实 <code>Dockerfile</code> 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。</p><h3 id="COPY"><a href="#COPY" class="headerlink" title="COPY"></a>COPY</h3><p>格式:</p><ul><li><code>COPY <源路径>... <目标路径></code></li><li><code>COPY ["<源路径1>",... "<目标路径>"]</code></li></ul><p>和 <code>RUN</code> 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。</p><p><code>COPY</code> 指令将从构建上下文目录中 <code><源路径></code> 的文件/目录复制到新的一层的镜像内的 <code><目标路径></code> 位置。比如:</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs gradle"><span class="hljs-keyword">COPY</span> <span class="hljs-keyword">package</span>.json <span class="hljs-regexp">/usr/</span>src<span class="hljs-regexp">/app/</span><br></code></pre></td></tr></table></figure><p><code><源路径></code> 可以是多个,甚至可以是通配符,其通配符规则要满足 <code>Go</code> 的 <code>filepath.Match</code> 规则,如:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">COPY</span><span class="language-bash"> hom* /mydir/</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> hom?.txt /mydir/</span><br></code></pre></td></tr></table></figure><p><code><目标路径></code> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 <code>WORKDIR</code> 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。</p><p>此外,还需要注意一点,使用 <code>COPY</code> 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 <code>Git</code> 进行管理的时候。</p><h3 id="ADD"><a href="#ADD" class="headerlink" title="ADD"></a>ADD</h3><p><code>ADD</code> 指令和 <code>COPY</code> 的格式和性质基本一致。但是在 <code>COPY</code> 基础上增加了一些功能。</p><p>比如 <code><源路径></code> 可以是一个 <code>URL</code>,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <code><目标路径></code> 去。下载后的文件权限自动设置为 <code>600</code>,如果这并不是想要的权限,那么还需要增加额外的一层 <code>RUN</code> 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 <code>RUN</code> 指令进行解压缩。所以不如直接使用 <code>RUN</code> 指令,然后使用 <code>wget</code> 或者 <code>curl</code> 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。</p><p>如果 <code><源路径></code> 为一个 <code>tar</code> 压缩文件的话,压缩格式为 <code>gzip</code>, <code>bzip2</code>以及 <code>xz</code> 的情况下,<code>ADD</code> 指令将会自动解压缩这个压缩文件到 <code><目标路径></code> 去。</p><p>在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 <code>ubuntu</code>中:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs routeros"><span class="hljs-keyword">FROM</span> scratch<br><span class="hljs-built_in">ADD</span> ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /<br><span class="hljs-built_in">..</span>.<br></code></pre></td></tr></table></figure><p>但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 <code>ADD</code> 命令了。</p><p>在 <code>Docker</code> 官方的 <code>Dockerfile 最佳实践文档</code> 中要求,尽可能的使用 <code>COPY</code>,因为 <code>COPY</code> 的语义很明确,就是复制文件而已,而 <code>ADD</code> 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 <code>ADD</code> 的场合,就是所提及的需要自动解压缩的场合。</p><p>另外需要注意的是,<code>ADD</code> 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。</p><p>因此在 <code>COPY</code> 和 <code>ADD</code> 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 <code>COPY</code> 指令,仅在需要自动解压缩的场合使用 <code>ADD</code>。</p><h3 id="CMD"><a href="#CMD" class="headerlink" title="CMD"></a>CMD</h3><p><code>CMD</code> 指令的格式和 <code>RUN</code> 相似,也是两种格式:</p><ul><li><code>shell</code> 格式:<code>CMD <命令></code></li><li><code>exec</code> 格式:<code>CMD ["可执行文件", "参数1", "参数2"...]</code></li><li>参数列表格式:<code>CMD ["参数1", "参数2"...]</code>。在指定了 <code>ENTRYPOINT</code>指令后,用 <code>CMD</code> 指定具体的参数。</li></ul><p>之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。<code>CMD</code> 指令就是用于指定默认的容器主进程的启动命令的。</p><p>在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,<code>ubuntu</code> 镜像默认的 <code>CMD</code> 是 <code>/bin/bash</code>,如果我们直接 <code>docker run -it ubuntu</code> 的话,会直接进入 <code>bash</code>。我们也可以在运行时指定运行别的命令,如 <code>docker run -it ubuntu cat /etc/os-release</code>。这就是用 <code>cat /etc/os-release</code> 命令替换了默认的 <code>/bin/bash</code> 命令了,输出了系统版本信息。</p><p>在指令格式上,一般推荐使用 <code>exec</code> 格式,这类格式在解析时会被解析为 <code>JSON</code> 数组,因此一定要使用双引号 <code>"</code>,而不要使用单引号。</p><p>如果使用 <code>shell</code> 格式的话,实际的命令会被包装为 <code>sh -c</code> 的参数的形式进行执行。比如:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">CMD</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-variable">$HOME</span></span><br></code></pre></td></tr></table></figure><p>在实际执行中,会将其变更为:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">CMD</span><span class="language-bash"> [ <span class="hljs-string">"sh"</span>, <span class="hljs-string">"-c"</span>, <span class="hljs-string">"echo <span class="hljs-variable">$HOME</span>"</span> ]</span><br></code></pre></td></tr></table></figure><p>这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。</p><p>提到 <code>CMD</code> 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。</p><p>Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 <code>upstart/systemd</code> 去启动后台服务,容器内没有后台服务的概念。</p><p>一些初学者将 <code>CMD</code> 写为:</p><figure class="highlight dos"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dos"><span class="hljs-built_in">CMD</span> service nginx <span class="hljs-built_in">start</span><br></code></pre></td></tr></table></figure><p>然后发现容器执行后就立即退出了。甚至在容器内去使用 <code>systemctl</code> 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。</p><p>对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。</p><p>而使用 <code>service nginx start</code> 命令,则是希望 upstart 来以后台守护进程形式启动 <code>nginx</code> 服务。而刚才说了 <code>CMD service nginx start</code> 会被理解为 <code>CMD [ "sh", "-c", "service nginx start"]</code>,因此主进程实际上是 <code>sh</code>。那么当 <code>service nginx start</code> 命令结束后,<code>sh</code> 也就结束了,<code>sh</code> 作为主进程退出了,自然就会令容器退出。</p><p>正确的做法是直接执行 <code>nginx</code> 可执行文件,并且要求以前台形式运行。比如:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs css">CMD <span class="hljs-selector-attr">[<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>]</span><br></code></pre></td></tr></table></figure><h3 id="ENTRYPOINT"><a href="#ENTRYPOINT" class="headerlink" title="ENTRYPOINT"></a>ENTRYPOINT</h3><p><code>ENTRYPOINT</code> 的格式和 <code>RUN</code> 指令格式一样,分为 <code>exec</code> 格式和 <code>shell</code>格式。</p><p><code>ENTRYPOINT</code> 的目的和 <code>CMD</code> 一样,都是在指定容器启动程序及参数。<code>ENTRYPOINT</code> 在运行时也可以替代,不过比 <code>CMD</code> 要略显繁琐,需要通过 <code>docker run</code> 的参数 <code>--entrypoint</code> 来指定。</p><p>当指定了 <code>ENTRYPOINT</code> 后,<code>CMD</code> 的含义就发生了改变,不再是直接的运行其命令,而是将 <code>CMD</code> 的内容作为参数传给 <code>ENTRYPOINT</code> 指令,换句话说实际执行时,将变为:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">ENTRYPOINT</span>></span> "<span class="hljs-tag"><<span class="hljs-name">CMD</span>></span>"<br></code></pre></td></tr></table></figure><p>那么有了 <code>CMD</code> 后,为什么还要有 <code>ENTRYPOINT</code> 呢?这种 <code><ENTRYPOINT> "<CMD>"</code> 有什么好处么?让我们来看几个场景。</p><h4 id="场景一:让镜像变成像命令一样使用"><a href="#场景一:让镜像变成像命令一样使用" class="headerlink" title="场景一:让镜像变成像命令一样使用"></a>场景一:让镜像变成像命令一样使用</h4><p>假设我们需要一个得知自己当前公网 <code>IP</code> 的镜像,那么可以先用 <code>CMD</code> 来实现:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">16.04</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update \</span><br><span class="language-bash"> && apt-get install -y curl \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/*</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [ <span class="hljs-string">"curl"</span>, <span class="hljs-string">"-s"</span>, <span class="hljs-string">"http://ip.cn"</span> ]</span><br></code></pre></td></tr></table></figure><p>假如我们使用 <code>docker build -t myip .</code> 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs routeros">$ docker <span class="hljs-built_in">run</span> myip<br>当前 IP:160.155.224.xx 来自:XX市 联通<br></code></pre></td></tr></table></figure><p>这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 <code>CMD</code> 中可以看到实质的命令是 <code>curl</code>,那么如果我们希望显示 HTTP 头信息,就需要加上 <code>-i</code> 参数。那么我们可以直接加 <code>-i</code> 参数给 <code>docker run myip</code> 么?</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs swift">$ docker run myip <span class="hljs-operator">-</span>i<br>docker: <span class="hljs-type">Error</span> response from daemon: invalid header field value <span class="hljs-string">"oci runtime error: container_linux.go:247: starting container process caused <span class="hljs-subst">\"</span>exec: <span class="hljs-subst">\\</span><span class="hljs-subst">\"</span>-i<span class="hljs-subst">\\</span><span class="hljs-subst">\"</span>: executable file not found in $PATH<span class="hljs-subst">\"</span><span class="hljs-subst">\n</span>"</span>.<br></code></pre></td></tr></table></figure><p>我们可以看到可执行文件找不到的报错,<code>executable file not found</code>。之前我们说过,跟在镜像名后面的是 <code>command</code>,运行时会替换 <code>CMD</code> 的默认值。因此这里的 <code>-i</code> 替换了原来的 <code>CMD</code>,而不是添加在原来的 <code>curl -s http://ip.cn</code> 后面。而 <code>-i</code> 根本不是命令,所以自然找不到。</p><p>那么如果我们希望加入 <code>-i</code> 这参数,我们就必须重新完整的输入这个命令:</p><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs arduino">$ docker run myip curl -s http:<span class="hljs-comment">//ip.cn -i</span><br></code></pre></td></tr></table></figure><p>这显然不是很好的解决方案,而使用 <code>ENTRYPOINT</code> 就可以解决这个问题。现在我们重新用 <code>ENTRYPOINT</code> 来实现这个镜像:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> ubuntu:<span class="hljs-number">16.04</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update \</span><br><span class="language-bash"> && apt-get install -y curl \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/*</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [ <span class="hljs-string">"curl"</span>, <span class="hljs-string">"-s"</span>, <span class="hljs-string">"http://ip.cn"</span> ]</span><br></code></pre></td></tr></table></figure><p>这次我们再来尝试直接使用 <code>docker run myip -i</code>:</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs pgsql">$ docker run myip<br>当前 IP:<span class="hljs-number">160.155</span><span class="hljs-number">.224</span>.xx 来自:XX市 联通<br><br>$ docker run myip -i<br>HTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">200</span> OK<br><span class="hljs-keyword">Server</span>: nginx/<span class="hljs-number">1.8</span><span class="hljs-number">.0</span><br><span class="hljs-type">Date</span>: Tue, <span class="hljs-number">22</span> Nov <span class="hljs-number">2016</span> <span class="hljs-number">05</span>:<span class="hljs-number">12</span>:<span class="hljs-number">40</span> GMT<br>Content-<span class="hljs-keyword">Type</span>: <span class="hljs-type">text</span>/html; charset=UTF<span class="hljs-number">-8</span><br>Vary: Accept-<span class="hljs-keyword">Encoding</span><br>X-Powered-<span class="hljs-keyword">By</span>: PHP/<span class="hljs-number">5.6</span><span class="hljs-number">.24</span><span class="hljs-number">-1</span>~dotdeb+<span class="hljs-number">7.1</span><br>X-<span class="hljs-keyword">Cache</span>: MISS from <span class="hljs-keyword">cache</span><span class="hljs-number">-2</span><br>X-<span class="hljs-keyword">Cache</span>-Lookup: MISS from <span class="hljs-keyword">cache</span><span class="hljs-number">-2</span>:<span class="hljs-number">80</span><br>X-<span class="hljs-keyword">Cache</span>: MISS from proxy<span class="hljs-number">-2</span>_6<br>Transfer-<span class="hljs-keyword">Encoding</span>: chunked<br>Via: <span class="hljs-number">1.1</span> <span class="hljs-keyword">cache</span><span class="hljs-number">-2</span>:<span class="hljs-number">80</span>, <span class="hljs-number">1.1</span> proxy<span class="hljs-number">-2</span>_6:<span class="hljs-number">8006</span><br><span class="hljs-keyword">Connection</span>: keep-alive<br><br>当前 IP:<span class="hljs-number">160.155</span><span class="hljs-number">.224</span>.xx 来自:XX市 联通<br></code></pre></td></tr></table></figure><p>可以看到,这次成功了。这是因为当存在 <code>ENTRYPOINT</code> 后,<code>CMD</code> 的内容将会作为参数传给 <code>ENTRYPOINT</code>,而这里 <code>-i</code> 就是新的 <code>CMD</code>,因此会作为参数传给 <code>curl</code>,从而达到了我们预期的效果。</p><h4 id="场景二:应用运行前的准备工作"><a href="#场景二:应用运行前的准备工作" class="headerlink" title="场景二:应用运行前的准备工作"></a>场景二:应用运行前的准备工作</h4><p>启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。</p><p>比如 <code>mysql</code> 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的 mysql 服务器运行之前解决。</p><p>此外,可能希望避免使用 <code>root</code> 用户去启动服务,从而提高安全性,而在启动服务前还需要以 <code>root</code> 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 <code>root</code> 身份执行,方便调试等。</p><p>这些准备工作是和容器 <code>CMD</code> 无关的,无论 <code>CMD</code> 为什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 <code>ENTRYPOINT</code> 中去执行,而这个脚本会将接到的参数(也就是 <code><CMD></code>)作为命令,在脚本最后执行。比如官方镜像 <code>redis</code> 中就是这么做的:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> alpine:<span class="hljs-number">3.4</span><br>...<br><span class="hljs-keyword">RUN</span><span class="language-bash"> addgroup -S redis && adduser -S -G redis redis</span><br>...<br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">"docker-entrypoint.sh"</span>]</span><br><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">6379</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [ <span class="hljs-string">"redis-server"</span> ]</span><br></code></pre></td></tr></table></figure><p>可以看到其中为了 <code>Redis</code> 服务创建了 <code>Redis</code> 用户,并在最后指定了 <code>ENTRYPOINT</code> 为 <code>docker-entrypoint.sh</code> 脚本。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-meta">#!/bin/sh</span><br>...<br><span class="hljs-comment"># allow the container to be started with `--user`</span><br><span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> = <span class="hljs-string">'redis-server'</span> -a <span class="hljs-string">"<span class="hljs-subst">$(id -u)</span>"</span> = <span class="hljs-string">'0'</span> ]; <span class="hljs-keyword">then</span><br> <span class="hljs-built_in">chown</span> -R redis .<br> <span class="hljs-built_in">exec</span> su-exec redis <span class="hljs-string">"<span class="hljs-variable">$0</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span><br><span class="hljs-keyword">fi</span><br><br><span class="hljs-built_in">exec</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span><br></code></pre></td></tr></table></figure><p>该脚本的内容就是根据 <code>CMD</code> 的内容来判断,如果是 <code>redis-server</code> 的话,则切换到 <code>redis</code> 用户身份启动服务器,否则依旧使用 <code>root</code> 身份执行。比如:</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs routeros">$ docker <span class="hljs-built_in">run</span> -it redis id<br><span class="hljs-attribute">uid</span>=0(root) <span class="hljs-attribute">gid</span>=0(root) <span class="hljs-attribute">groups</span>=0(root)<br></code></pre></td></tr></table></figure><h3 id="ENV"><a href="#ENV" class="headerlink" title="ENV"></a>ENV</h3><p>格式有两种:</p><ul><li><code>ENV <key> <value></code></li><li><code>ENV <key1>=<value1> <key2>=<value2>...</code></li></ul><p>这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 <code>RUN</code>,还是运行时的应用,都可以直接使用这里定义的环境变量。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs routeros">ENV <span class="hljs-attribute">VERSION</span>=1.0 <span class="hljs-attribute">DEBUG</span>=on \<br> <span class="hljs-attribute">NAME</span>=<span class="hljs-string">"Happy Feet"</span><br></code></pre></td></tr></table></figure><p>这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 <code>Shell</code> 下的行为是一致的。</p><p>定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方 <code>node</code> 镜像 <code>Dockerfile</code> 中,就有类似这样的代码:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">ENV</span> NODE_VERSION <span class="hljs-number">7.2</span>.<span class="hljs-number">0</span><br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> curl -SLO <span class="hljs-string">"https://nodejs.org/dist/v<span class="hljs-variable">$NODE_VERSION</span>/node-v<span class="hljs-variable">$NODE_VERSION</span>-linux-x64.tar.xz"</span> \</span><br><span class="language-bash"> && curl -SLO <span class="hljs-string">"https://nodejs.org/dist/v<span class="hljs-variable">$NODE_VERSION</span>/SHASUMS256.txt.asc"</span> \</span><br><span class="language-bash"> && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \</span><br><span class="language-bash"> && grep <span class="hljs-string">" node-v<span class="hljs-variable">$NODE_VERSION</span>-linux-x64.tar.xz\$"</span> SHASUMS256.txt | <span class="hljs-built_in">sha256sum</span> -c - \</span><br><span class="language-bash"> && tar -xJf <span class="hljs-string">"node-v<span class="hljs-variable">$NODE_VERSION</span>-linux-x64.tar.xz"</span> -C /usr/local --strip-components=1 \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> <span class="hljs-string">"node-v<span class="hljs-variable">$NODE_VERSION</span>-linux-x64.tar.xz"</span> SHASUMS256.txt.asc SHASUMS256.txt \</span><br><span class="language-bash"> && <span class="hljs-built_in">ln</span> -s /usr/local/bin/node /usr/local/bin/nodejs</span><br></code></pre></td></tr></table></figure><p>在这里先定义了环境变量 <code>NODE_VERSION</code>,其后的 <code>RUN</code> 这层里,多次使用 <code>$NODE_VERSION</code> 来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新 <code>7.2.0</code> 即可,<code>Dockerfile</code> 构建维护变得更轻松了。</p><p>下列指令可以支持环境变量展开:<code>ADD</code>、<code>COPY</code>、<code>ENV</code>、<code>EXPOSE</code>、<code>LABEL</code>、<code>USER</code>、<code>WORKDIR</code>、<code>VOLUME</code>、<code>STOPSIGNAL</code>、<code>ONBUILD</code>。</p><p>可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份 <code>Dockerfile</code> 制作更多的镜像,只需使用不同的环境变量即可。</p><h3 id="VOLUME"><a href="#VOLUME" class="headerlink" title="VOLUME"></a>VOLUME</h3><p>格式为:</p><ul><li><code>VOLUME ["<路径1>", "<路径2>"...]</code></li><li><code>VOLUME <路径></code></li></ul><p>之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 <code>Dockerfile</code> 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">VOLUME</span><span class="language-bash"> /data</span><br></code></pre></td></tr></table></figure><p>这里的 <code>/data</code> 目录就会在运行时自动挂载为匿名卷,任何向 <code>/data</code> 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">run</span><span class="language-bash"> -d -v mydata:/data xxxx</span><br></code></pre></td></tr></table></figure><p>在这行命令中,就使用了 <code>mydata</code> 这个命名卷挂载到了 <code>/data</code> 这个位置,替代了 <code>Dockerfile</code> 中定义的匿名卷的挂载配置。</p><h3 id="EXPOSE"><a href="#EXPOSE" class="headerlink" title="EXPOSE"></a>EXPOSE</h3><p>格式为 <code>EXPOSE <端口1> [<端口2>...]</code>。</p><p><code>EXPOSE</code> 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 <code>Dockerfile</code> 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 <code>docker run -P</code> 时,会自动随机映射 <code>EXPOSE</code> 的端口。</p><p>此外,在早期 <code>Docker</code> 版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中,因此所有容器互相之间都可以直接访问,这样存在一定的安全性问题。于是有了一个 <code>Docker</code> 引擎参数 <code>--icc=false</code>,当指定该参数后,容器间将默认无法互访,除非互相间使用了 <code>--links</code> 参数的容器才可以互通,并且只有镜像中 <code>EXPOSE</code> 所声明的端口才可以被访问。这个 <code>--icc=false</code> 的用法,在引入了 <code>docker network</code> 后已经基本不用了,通过自定义网络可以很轻松的实现容器间的互联与隔离。</p><p>要将 <code>EXPOSE</code> 和在运行时使用 <code>-p <宿主端口>:<容器端口></code> 区分开来。<code>-p</code>,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 <code>EXPOSE</code> 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。</p><h3 id="WORKDIR"><a href="#WORKDIR" class="headerlink" title="WORKDIR"></a>WORKDIR</h3><p>格式为 <code>WORKDIR <工作目录路径></code>。</p><p>使用 <code>WORKDIR</code> 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,<code>WORKDIR</code> 会帮你建立目录。</p><p>之前提到一些初学者常犯的错误是把 <code>Dockerfile</code> 等同于 <code>Shell</code> 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">UN <span class="hljs-built_in">cd</span> /app<br>RUN <span class="hljs-built_in">echo</span> <span class="hljs-string">"hello"</span> > world.txt<br></code></pre></td></tr></table></figure><p>如果将这个 <code>Dockerfile</code> 进行构建镜像运行后,会发现找不到 <code>/app/world.txt</code> 文件,或者其内容不是 <code>hello</code>。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 <code>Dockerfile</code> 中,这两行 <code>RUN</code> 命令的执行环境根本不同,是两个完全不同的容器。这就是对 <code>Dockerfile</code> 构建分层存储的概念不了解所导致的错误。</p><p>之前说过每一个 <code>RUN</code> 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 <code>RUN cd /app</code> 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。</p><p>因此如果需要改变以后各层的工作目录的位置,那么应该使用 <code>WORKDIR</code>指令。</p><h3 id="DockerFile总结"><a href="#DockerFile总结" class="headerlink" title="DockerFile总结"></a>DockerFile总结</h3><h4 id="CMD和RUN区别"><a href="#CMD和RUN区别" class="headerlink" title="CMD和RUN区别?"></a><strong><code>CMD</code>和<code>RUN</code>区别?</strong></h4><p><code>CMD</code>是容器启动的时候会执行的命令</p><p><code>RUN</code>是打包镜像的时候执行的命令</p><p>如果在打包的时候需要更改某一个目录和文件的权限, 需要使用RUN更改, CMD不会生效</p><h4 id="Dockerfile关键字"><a href="#Dockerfile关键字" class="headerlink" title="Dockerfile关键字"></a><strong>Dockerfile关键字</strong></h4><p>**LABEL *<em>:</em>功能是为镜像指定标签*</p><p><strong>FORM</strong>:基础镜像,表明当前镜像是基于那么镜像的</p><p><strong>MAINTAINER</strong> :镜像维护者的名字和邮箱地址</p><p><strong>RUN</strong>:容器构建时需要用到的命令</p><p><strong>EXPOSE</strong>:当前容器对外暴露的端口</p><p><strong>WORKDIR</strong>:指定在创建容器后,终端默认登录的工作目录。(也就是你登录进某个容器的时候,默认的目录)</p><p><strong>ENV</strong>:用来构建镜像过程中设置环境环境(ENV MY_PATH /usr/mytest、WORKDIR $MY_PATH)</p><p>用法:env key=value或 env key value</p><p><strong>ADD</strong>:将宿主机目录的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包(类似于absible的某个模块)</p><p><strong>COPY</strong>:类似ADD,拷贝文件和目录到镜像中(COPY src dest、COPY[“src”,”dest”])</p><p><strong>VOLUME</strong>:容器数据卷,指定数据卷目录,用于数据保存和持久化工作</p><p><strong>CMD</strong>:<strong>指定一个容器启动时要运行的命令。</strong>dockerfile中可以有多个CMD,但是生效的只有最后一个,CMD会被docker run 之后 的参数替换。</p><p><strong>ENTRPOINT</strong>:<strong>指定一个容器启动时要运行的命令。</strong>有多个会追加。在 Docker 中,ENTRYPOINT 通常用于设置容器的主要执行命令,而 CMD 指令则用于设置默认的执行参数。如果同时使用了 ENTRYPOINT 和 CMD,那么 CMD 中的参数会传递给 ENTRYPOINT 指定的命令。</p><p><strong>ONBUILD</strong>:触发器,当构建一个被继承的 Dockerfile时运行命令,父镜像在被子继承后父镜像的 ONBUILD被触发(子镜像继承了父镜像 的dockerfile,父镜像有ONBUILD定义,那么这个子镜像继承过去了ONBUILD,ONBUILD会执行)</p><h4 id="编写注意点"><a href="#编写注意点" class="headerlink" title="编写注意点"></a>编写注意点</h4><ol><li>尽量少写RUN</li><li>多个命令如果可以拼接在一起的话, 尽量拼接在一起</li><li>清理冗余的垃圾文件</li></ol><h4 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h4><p>CMD和ENTRYPIOINT 必须要有一个,CMD可以被覆盖,如果有ENTRYPIOINT的话,CMD就是ENTRYPIOINT的参数。dockerfile的ENTRYPIOINT 对应k8s的yaml文件的COMMAND,CMD对应ar</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">说明:<br><span class="hljs-keyword">FROM</span>:继承基础镜像<br><span class="hljs-keyword">MAINTAINER</span>:镜像制作作者信息<br><span class="hljs-keyword">RUN</span><span class="language-bash">:用来执行shell命令</span><br><span class="hljs-keyword">EXPOSE</span>:暴露端口号<br><span class="hljs-keyword">CMD</span><span class="language-bash">:启动容器默认执行的命令</span><br><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash">:启动容器真正执行的命令</span><br><span class="hljs-keyword">VOLUME</span><span class="language-bash">:创建挂载点</span><br><span class="hljs-keyword">ENV</span>:配置环境变量<br><span class="hljs-keyword">ADD</span><span class="language-bash">:复制文件到容器</span><br><span class="hljs-keyword">COPY</span><span class="language-bash">:复制文件到容器</span><br><span class="hljs-keyword">WORKDIR</span><span class="language-bash">:设置容器的工作目录</span><br><span class="hljs-keyword">USER</span>:容器使用的用户<br><br><br><span class="hljs-keyword">FROM</span> centos:<span class="hljs-number">8</span> <span class="hljs-comment">#初始镜像,</span><br><span class="hljs-keyword">LABEL</span><span class="language-bash"> maintainer=<span class="hljs-string">"test dockerfile"</span> <span class="hljs-comment">#打标签</span></span><br><span class="hljs-keyword">LABEL</span><span class="language-bash"> <span class="hljs-built_in">test</span>=dockerfile</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> useradd dot <span class="hljs-comment">#docker build时运行的命令</span></span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">mkdir</span> /opt/dot</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [ <span class="hljs-string">"sh"</span>, <span class="hljs-string">"-c"</span>, <span class="hljs-string">"echo 1"</span>] <span class="hljs-comment">#在启动docker时运行,如docker run</span></span><br><span class="hljs-comment">#RUN useradd dot && /opt/dot</span><br><span class="hljs-keyword">FROM</span> centos:<span class="hljs-number">8</span><br><br><span class="hljs-keyword">LABEL</span><span class="language-bash"> maintainer=<span class="hljs-string">"test dockerfile"</span></span><br><span class="hljs-keyword">LABEL</span><span class="language-bash"> <span class="hljs-built_in">test</span>=dockerfile</span><br><br><span class="hljs-keyword">ENV</span> test_env1 env1<br><span class="hljs-keyword">ENV</span> test_env2 env2<br><span class="hljs-keyword">RUN</span><span class="language-bash"> useradd dot</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">mkdir</span> /opt/dot</span><br><br><span class="hljs-comment">#ENTRYPOINT ["echo"]</span><br><span class="hljs-keyword">ENV</span> env1=test1 env2=test2 <span class="hljs-comment">#设置环境变量</span><br><br><span class="hljs-keyword">ADD</span><span class="language-bash"> ./index.tar.gz /opt/ <span class="hljs-comment">#将宿主机的文件,拷贝到容器内并会自动解压包</span></span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> ./index.tar.gz /opt/dot/ <span class="hljs-comment">#将宿主机的文件拷贝到容器,但是不会解压。需要注意的是,宿主机都要采用相对路径</span></span><br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /opt/dot <span class="hljs-comment">#设置容器内程序的工作目录</span></span><br><span class="hljs-keyword">USER</span> <span class="hljs-number">1000</span> <span class="hljs-comment">#指定使用的用户</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> <span class="hljs-built_in">pwd</span> ; <span class="hljs-built_in">ls</span></span><br><span class="hljs-comment">#RUN useradd dot && /opt/dot</span><br><span class="hljs-comment">#分部制作镜像可以大大减小镜像的体积</span><br><span class="hljs-comment"># build step</span><br><span class="hljs-keyword">FROM</span> golang:<span class="hljs-number">1.14</span>.<span class="hljs-number">4</span>-alpine as builder<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /opt</span><br><br><span class="hljs-keyword">COPY</span><span class="language-bash"> main.go /opt</span><br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> go build /opt/main.go </span><br><br><span class="hljs-keyword">CMD</span><span class="language-bash"> <span class="hljs-string">"./main"</span></span><br><br><span class="hljs-comment"># create real app image</span><br><br><span class="hljs-keyword">FROM</span> alpine:<span class="hljs-number">3.8</span> <span class="hljs-comment">#将上面编译好的文件拷贝到新镜像,通俗理解过上面的过程是为了编译镜像,这一个from才是制作真正的镜像</span><br><br><span class="hljs-keyword">COPY</span><span class="language-bash"> --from=builder /opt/main / <span class="hljs-comment">#builder是FROM golang:1.14.4-alpine过程的别名</span></span><br><br><span class="hljs-keyword">CMD</span><span class="language-bash"> <span class="hljs-string">"./opt/main"</span></span><br></code></pre></td></tr></table></figure><h1 id="pause容器"><a href="#pause容器" class="headerlink" title="pause容器"></a>pause容器</h1><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>简介:Pause容器 全称infrastucture container(又叫infra)基础容器,作为init pod存在,其他pod都会从pause 容器中fork出来</p><p>1、每个Pod里运行着一个特殊的被称之为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,<br>2、因此他们之间通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中。<br>3、同一个Pod里的容器之间仅需通过localhost就能互相通信。</p><p><strong>pause容器主要为每个业务容器提供以下功能:</strong></p><figure class="highlight armasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs armasm">① PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。<br>② 网络命名空间:Pod中的多个容器能够访问同一个<span class="hljs-built_in">IP</span>和端口范围。<br>③ IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。<br>④ UTS命名空间:Pod中的多个容器共享一个主机名;Volumes(共享存储卷):<br>⑤ Pod中的各个容器可以访问在Pod级别定义的Volumes。 <br></code></pre></td></tr></table></figure><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205112334500.png" alt="img"> </p><h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><p>kubernetes中的pause容器主要为每个业务容器提供以下功能:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs markdown"><span class="hljs-bullet">1.</span> 在pod中担任Linux命名空间共享的基础;<br><span class="hljs-bullet">2.</span> 启用pid命名空间,开启init进程。<br></code></pre></td></tr></table></figure><h4 id="在节点上运行一个pause容器"><a href="#在节点上运行一个pause容器" class="headerlink" title="在节点上运行一个pause容器"></a>在节点上运行一个pause容器</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -d --name pause -p 8880:80 da86e6ba6ca1<br></code></pre></td></tr></table></figure><p><img src="https://myfiles-1259079469.cos.ap-beijing.myqcloud.com/imgs/202205112334380.png" alt="img"></p><h4 id="运行一个nginx容器,"><a href="#运行一个nginx容器," class="headerlink" title="运行一个nginx容器,"></a>运行一个nginx容器,</h4><p>1、配置一个nginx.conf,</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs pgsql"> cat <span class="hljs-symbol"><<EOF >></span> nginx.conf<br>error_log stderr;<br>events { worker_connections <span class="hljs-number">1024</span>; }<br>http {<br> access_log /dev/stdout combined;<br> <span class="hljs-keyword">server</span> {<br> <span class="hljs-keyword">listen</span> <span class="hljs-number">80</span> default_server;<br> server_name example.com www.example.com;<br> <span class="hljs-keyword">location</span> / {<br> proxy_pass http://<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">2368</span>;<br> }<br> }<br>}<br>EOF<br></code></pre></td></tr></table></figure><p>2、运行一个nginx容器,nginx将为 <code>localhost:2368</code> 创建一个代理。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs routeros">docker <span class="hljs-built_in">run</span> -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf <span class="hljs-attribute">--net</span>=container:pause <br><span class="hljs-attribute">--ipc</span>=container:pause <span class="hljs-attribute">--pid</span>=container:pause nginx<br></code></pre></td></tr></table></figure><h4 id="然后再为-ghost-创建一个应用容器,这是一款博客软件"><a href="#然后再为-ghost-创建一个应用容器,这是一款博客软件" class="headerlink" title="然后再为 ghost 创建一个应用容器,这是一款博客软件"></a>然后再为 <a href="https://github.com/TryGhost/Ghost">ghost</a> 创建一个应用容器,这是一款博客软件</h4><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">docker <span class="hljs-built_in">run</span> -d --name ghost <span class="hljs-attribute">--net</span>=container:pause <span class="hljs-attribute">--ipc</span>=container:pause <span class="hljs-attribute">--pid</span>=container:pause ghost<br></code></pre></td></tr></table></figure><h4 id="解析"><a href="#解析" class="headerlink" title="解析"></a>解析</h4><p>1、pause容器将内部的80端口映射到宿主机的8880端口,pause容器在宿主机上设置好了网络namespace后,nginx容器加入到该网络namespace中</p><p>2、nginx容器启动的时候指定了 –net=container:pause ,ghost容器同样加入到了该网络namespace中,这样三个容器就共享了网络,互相之间</p><p>就可以使用 localhost 直接通信</p><p>3、 –ipc=contianer:pause –pid=container:pause 就是三个容器处于同一个namespace中,init进程为 pause</p><p>4、这时我们进入到ghost容器中查看进程情况</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># ps aux</span><br>USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND<br>root 1 0.0 0.0 1024 4 ? Ss 13:49 0:00 /pause<br>root 5 0.0 0.1 32432 5736 ? Ss 13:51 0:00 nginx: master p<br>systemd+ 9 0.0 0.0 32980 3304 ? S 13:51 0:00 nginx: worker p<br>node 10 0.3 2.0 1254200 83788 ? Ssl 13:53 0:03 node current/in<br>root 79 0.1 0.0 4336 812 pts/0 Ss 14:09 0:00 sh<br>root 87 0.0 0.0 17500 2080 pts/0 R+ 14:10 0:00 ps aux<br></code></pre></td></tr></table></figure><p>在ghost容器中同时可以看到pause和nginx容器的进程,并且pause容器的PID是1。而在kubernetes中容器的PID=1的进程即为容器本身的业务进程 </p><h1 id="拓展-1"><a href="#拓展-1" class="headerlink" title="拓展"></a>拓展</h1><h3 id="配置私有仓库-1"><a href="#配置私有仓库-1" class="headerlink" title="配置私有仓库"></a>配置私有仓库</h3><ol><li>工具下载</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum install httpd-tools -y<br></code></pre></td></tr></table></figure><ol start="2"><li>创建目录</li></ol><ul><li>秘钥存储目录</li></ul> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> -p /data/docker/registry/auth<br></code></pre></td></tr></table></figure><ul><li>镜像目录</li></ul> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> -p /data/docker/registry/mirror<br></code></pre></td></tr></table></figure><ol start="3"><li>生成秘钥</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">htpasswd -Bbn admin 123456 > /data/docker/registry/auth/htpasswd<br></code></pre></td></tr></table></figure><ol start="4"><li>启动镜像</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run -d --restart=always -p 6000:5000 --name register-auth \<br> -v /data/docker/registry/auth:/var/lib/registry/auth \<br> -v /data/docker/registry/mirror:/var/lib/registry \<br> -e <span class="hljs-string">"REGISTRY_AUTH=htpasswd"</span> \<br> -e <span class="hljs-string">"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"</span> \<br> -e <span class="hljs-string">"REGISTRY_AUTH_HTPASSWD_PATH=/var/lib/registry/auth/htpasswd"</span> \<br> registry<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>K8S</category>
</categories>
<tags>
<tag>k8s</tag>
</tags>
</entry>
<entry>
<title>测试文章</title>
<link href="/2024/08/11/test/"/>
<url>/2024/08/11/test/</url>
<content type="html"><![CDATA[<p>这是一篇测试文章<br><img src="/2024/08/11/test/t.jpg" alt="测试图片"></p>]]></content>
<categories>
<category>Golang</category>
</categories>
<tags>
<tag>原创</tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/2024/08/11/hello-world/"/>
<url>/2024/08/11/hello-world/</url>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo new <span class="hljs-string">"My New Post"</span><br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo server<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo generate<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ hexo deploy<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
</entry>
</search>