-
Notifications
You must be signed in to change notification settings - Fork 0
/
packages.tex
383 lines (283 loc) · 11.5 KB
/
packages.tex
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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
\cleardoublepage
\phantomsection
\chapter{Packages}
\begin{quote}
\textit{A little copying is better than a little dependency.} --- Go Proverbs
\end{quote}
Go encourages and provides mechanisms for code reusability. Packages
are one of the building block for code reusability. We have seen
other code reusability mechanisms like functions in the earlier
chapters.
This chapter will explain everything you need to know about
packages\index{package}. In the previous programs, there was a clause
at the beginning of every source files like this:
\begin{lstlisting}[numbers=none]
package main
\end{lstlisting}
That clause was declaring the name of the package as \texttt{main}.
The package name was \texttt{main} because the program was executable.
For non-executable programs, you can give a different meaningful short
name as the package name.
Most of the previous programs imported other packages like this:
\begin{lstlisting}[numbers=none]
import "fmt"
\end{lstlisting}
Sometimes the import was within parenthesis (factored imports) for
multiple packages:
\begin{lstlisting}[numbers=none]
import (
"fmt"
"time"
)
\end{lstlisting}
Importing packages gives access to functionalities provided by those
packages.
Packages helps you to create modular reusable programs. Go programs
are organized using packages. Every source file will be associated
with a package. Basically, package is a collection of source files.
A package generally consists of elements like constants, types,
variables and functions which are accessible across all the source
files. The source files should should start with a statement
declaring the name of the package. The package name should be a
meaningful short name. This is important because normally the
exported names within the package will be accessed with the package
name as a prefix.
The Go standard library has many packages. Each package will be
related to certain ideas.
\section{Creating a Package}
\index{package!creating}
Consider this file named \texttt{circle1.go} which belongs to
package \texttt{main}:
\begin{lstlisting}
package main
const pi float64 = 3.14
type Circle struct {
Radius float64
}
\end{lstlisting}
Another file named \texttt{circle2.go} in the same directory:
\begin{lstlisting}
package main
func (c Circle) Area() float64 {
return pi * c.Radius * c.Radius
}
\end{lstlisting}
Yet another file named \texttt{circle3.go}:
\begin{lstlisting}
package main
import "fmt"
var c Circle
func main() {
c = Circle{3.5}
fmt.Println(c.Area())
}
\end{lstlisting}
As you can see above all the above source files belongs
to \texttt{main} package.
You can build and run it like this:
\begin{lstlisting}[numbers=none]
$ go build -o circle
$ ./circle
38.465
\end{lstlisting}
Alternatively, you can use \texttt{go run}:
\begin{lstlisting}[numbers=none]
$ go run *.go
38.465
\end{lstlisting}
The final Go program is a created by joining multiple files. The
package is a container for your code.
\section{Package Initialization}
When you run a Go program, all the associated packages initialize in a
particular order. The package level variables initialize as per the
order of declaration. However, if there is any dependency on
initialization, that is resolved first.
Consider this example:
\begin{lstlisting}[numbers=none]
package varinit
var a = b + 2
var b = 1
\end{lstlisting}
In the above program, the variable \texttt{a} is depending on the
value of variable \texttt{b}. Therefore, the variable \texttt{b}
initialize first and the variable \texttt{a} is the second. If you
import the above package from different other packages in the same
program, the variable initialization happens only once.
If the expression for variable initialization is complicated, you can
use a function to return the value. There is another approach
possible for initializing variables with complex expressions, that is
by using the special \textit{init} function. The Go runtime executes
the \textit{init} function only once. Here is an example:
\lstinputlisting{code/packages/config/config.go}
The \textit{init} function cannot be called or even referred from the
program -- it's going to produce a compile error. Also,
the \textit{init} function should not return any value.
\section{Documenting Packages}
You can write documentation for the
package\index{package!documentation} in the form of comment before the
declarion of package name. The comment should begin with the
word \textit{Package} followed by the name of the package. Here is an
example:
\begin{lstlisting}[numbers=none]
// Package hello gives various greeting messages
package hello
\end{lstlisting}
If the package is defined in multiple files, you may create a file
named \textit{doc.go}. The \textit{doc.go} file is just a naming
convention. You can write multi-line comment using \texttt{/* ... */}
syntax. You can write source code with tab-indentation which will be
highlighted and displayed using monospace font in HTML format.
Here is an example from the \textit{http} package \textit{doc.go}
file.
\begin{lstlisting}[numbers=none]
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package http provides HTTP client and server implementations.
Get, Head, Post, and PostForm make HTTP (or HTTPS) requests:
resp, err := http.Get("http://example.com/")
...
<...strip lines...>
*/
package http
\end{lstlisting}
Many lines are stripped from the above example where its marked. As
you can see the above documentation file starts with copyright notice.
But the copyright notice is using single line comment multiple times.
This notice will be ignored when generating documentation. And the
documentation is written within multi-line comments. At the end of
file, the package name is also declared.
\section{Publishing Packages}
Unlike other mainstream languages, Go doesn't have a central package
server. You can publish your code directly to any version control
system repositories\index{package!publish}. Git is most widely used
VCS used to publish packages, but you can also use Mercurial or
Bazaar.
Here are few example packages:
\begin{itemize}
\item \url{https://github.com/auth0/go-jwt-middleware}
\item \url{https://github.com/blevesearch/bleve}
\item \url{https://github.com/dgrijalva/jwt-go}
\item \url{https://github.com/elazarl/go-bindata-assetfs}
\item \url{https://github.com/google/jsonapi}
\item \url{https://github.com/gorilla/mux}
\item \url{https://github.com/jpillora/backoff}
\item \url{https://github.com/kelseyhightower/envconfig}
\item \url{https://github.com/lib/pq}
\item \url{https://github.com/pkg/errors}
\item \url{https://github.com/thoas/stats}
\item \url{https://github.com/urfave/negroni}
\end{itemize}
You can use \texttt{go get} command to get these packages locally. Go
1.11 release introduced the module support. The modules can be used
to manage external dependant packages.
\section{Module}
A \textit{module}\index{module} is a collection of Go packages with
well defined name module and dependency requirements. Also, the module
has reproducible builds.
Modules use semantic versioning. The format of version should
vMAJOR.MINOR.PATCH. For example, v0.1.1, v1.3.1, or v2.0.0. Note
that the \textit{v} prefix is mandatory.
There should be a file named \textit{go.mod} at the top-level
directory. This file is used to declare the name of the module and
list dependencies.
The minimal version selection algorithm is used to select the versions
of all modules used in a build. For each module in a build, the
version selected by minimal version selection is always the
semantically highest of the versions explicitly listed by a require
directive in the main module or one of its dependencies.\\
You can see an explanation of the algorithm here:\\
\url{https://research.swtch.com/vgo-mvs}
\subsection{Creating a module}
The Go tool has support for creating modules. You can use
the \textit{mod} command to manage module.
To initialize a new module, use \textit{mod init} command with name of
module as argument. Normally the name will be same as the publishing
location. Here is an example:
\begin{lstlisting}[numbers=none]
mkdir hello
cd hello
go mod init github.com/baijum/hello
\end{lstlisting}
In the above example, the name is given
as \texttt{github.com/baijum/hello}. This command is going to create
file named \texttt{go.mod} and the content of that file will be like
this:
\begin{lstlisting}[numbers=none]
module github.com/baijum/hello
go 1.20
\end{lstlisting}
As of now there are no dependencies. That is the reason
the \texttt{go.mod} file doesn't list any dependencies.
Let's create a \texttt{hello.go} with \texttt{github.com/lib/pq}
as a dependency.
\begin{lstlisting}[numbers=none]
package main
import (
"database/sql"
_ "github.com/lib/pq"
)
func main() {
sql.Open("postgres",
"host=lh port=5432 user=gt dbname=db password=secret")
}
\end{lstlisting}
Note: The imported package is the driver used by the \textit{sql} package.
You will see the \texttt{mod.mod} updated with dependency.
\begin{lstlisting}[numbers=none]
module github.com/github.com/hello
go 1.20
require github.com/lib/pq v1.10.9
\end{lstlisting}
There will be another auto-generated file named \texttt{go.sum} which
is used for validation. You can commit both these files to your
version control system.
\section{Moving Type Across Packages}
When you refactoring a large package into smaller package or
separating certain features into another package, moving types will be
required. But moving types will be difficult as it may introduce
backward compatibility and it may affect existing consumer packages.
Go has support for type aliases to solve this problem. Type
alias\index{type!alias} can be declared as given in this example:
\begin{lstlisting}[numbers=none]
type NewType = OldType
\end{lstlisting}
Type alias can be removed once all the dependant packages migrate to
use import path.
\section{Exercises}
{\bf Exercise 1:} Create a package named \texttt{rectangle} with
exported functions to calculate area and perimeter for the given
rectangle.
\textbf{Solution:}
The name of the package could be \texttt{rectangle}. Here is the
program:
\begin{lstlisting}[numbers=none]
// Package rectangle provides functions to calculate area
// and perimeter for rectangle.
package rectangle
// Area calculate area of the given rectangle
func Area(width, height float64) float64 {
return width * height
}
// Perimeter calculate area of the given rectangle
func Perimeter(width, height float64) float64 {
return 2 * (width + height)
}
\end{lstlisting}
As you can see above, the source file starts with package
documentation. Also you can see the documentation for all exported
functions.
\subsection{Additional Exercises}
Answers to these additional exercises are given in the Appendix A.
{\bf Problem 1:} Create a package with 3 source files and
another \textit{doc.go} for documentation. The package should provide
functions to calculate areas for circle, rectangle, and triangle.
\section*{Summary}
This chapter explained packages in Go programming. Packages are a collection of
related Go source files that are compiled together to form a single unit. They
are one of the building blocks of a reusable Go program. This chapter explained
how to create packages, document packages, and publish packages. It also covered
modules and their usage. Finally, it explained how to move types across packages
during refactoring. By understanding packages, you can write more modular and
reusable Go programs.