This repository has been archived by the owner on Jan 9, 2019. It is now read-only.
forked from miekg/gobook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
go-beyond.tex
438 lines (395 loc) · 16.1 KB
/
go-beyond.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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
\epi{``Go has pointers but not pointer arithmetic. You cannot use a pointer
variable to walk through the bytes of a string.''}{\textit{Go For C++
Programmers}\\{\textsc{GO AUTHORS}}}
\noindent{}
Go has pointers.
There is however no pointer arithmetic, so they act more like
references than pointers that you may know from C. Pointers
are useful.
Remember that when you call a function in Go, the variables are
\emph{pass-by-value}. So, for efficiency and the possibility to modify a
passed value \emph{in} functions we have pointers.
You declare a pointer by prefixing the type with an
'\key{*}':
\lstinline{var p *int}. Now \var{p} is a pointer to an integer value.
All newly declared variables are assigned their zero value and pointers
are no different. A newly declared pointer, or just a pointer that points to
nothing, has a \first{nil}{nil}-value. In other languages this is often called
a NULL pointer in Go it is just \var{nil}. To make
a pointer point to something you can use the \first{address-of operator}{operator!address-of}
(\func{\&}), which we demonstrate here:
\begin{lstlisting}[caption=Use of a pointer,label=src:pointers]
var p *int
fmt.Printf("%v", p) |\coderemark{Prints \var{nil}}|
var i int |\coderemark{Declare integer variable \var{i}}|
p = &i |\coderemark{Make \var{p} point to \var{i}}|
fmt.Printf("%v", p) |\coderemark{Prints something like \var{0x7ff96b81c000a}}|
\end{lstlisting}
De-referencing a pointer is done by prefixing the pointer variable with
'\type{*}':
\begin{lstlisting}[caption=Dereferencing a pointer,label=src:deref]
p = &i |\coderemark{Take the address of \var{i}}|
*p = 8 |\coderemark{Change the value of \var{i}}|
fmt.Printf("%v\n", *p) |\coderemark{Prints 8}|
fmt.Printf("%v\n", i) |\coderemark{Idem}|
\end{lstlisting}
\label{main:pointer arithmetic}
As said, there is no pointer arithmetic, so if you write:
\lstinline{*p++}, it is interpreted as \lstinline{(*p)++}: first
reference and then increment the value.\index{operator!increment}
\footnote{See exercise \ref{ex:pointer arithmetic}.}
\section{Allocation}
Go also has garbage collection, meaning that you don't have to worry about
memory deallocation.
To allocate memory Go has two primitives, \key{new} and \key{make}. They do different
things and apply to different types, which can be confusing, but the
rules are simple.
The following sections show how to handle allocation
in Go and hopefully clarifies the somewhat artificial distinction between
\first{\key{new}}{built-in!new} and \first{\key{make}}{built-in!make}.
\subsection{Allocation with new}
\label{sec:allocation with new}
The built-in function \key{new} is
essentially the same as its namesakes in other languages: \func{new(T)}
allocates zeroed storage for a new item of type \type{T} and returns its
address, a value of type \type{*T}. In Go terminology, it returns a pointer to
a newly allocated zero value of type \type{T}. This is important to
remember:
\begin{lbar}[]
\key{new} returns a \emph{pointer}.
\end{lbar}
This
means a user of the data structure can create one with \key{new} and get
right to work. For example, the documentation for \func{bytes.Buffer} states
that ``the zero value for Buffer is an empty buffer ready to use.''
Similarly, \func{sync.Mutex} does not have an explicit constructor or Init
method. Instead, the zero value for a \func{sync.Mutex} is defined to be an
unlocked mutex.
The zero-value-is-useful property works transitively. Consider this type
declaration. See section ``\titleref{sec:defining your own}'' on page
\pageref{sec:defining your own}.
\begin{lstlisting}
type SyncedBuffer struct {
lock sync.Mutex
buffer bytes.Buffer
}
\end{lstlisting}
Values of type \type{SyncedBuffer} are also ready to use immediately upon
allocation or just declaration. In this snippet, both \var{p} and
\var{v} will work
correctly without further arrangement.
\begin{lstlisting}
p := new(SyncedBuffer) |\coderemark{Type *SyncedBuffer, ready to use}|
var v SyncedBuffer |\coderemark{Type SyncedBuffer, idem}|
\end{lstlisting}
\subsection{Allocation with make}
\label{sec:allocation with make}
Back to allocation. The built-in function \func{make(T, args)} serves a purpose
different from \func{new(T)}. It creates slices, maps, and channels \emph{only}, and
it returns an initialized (not zero) value of type \type{T}, not
\type{*T}. The reason
for the distinction is that these three types are, under the covers,
references to data structures that must be initialized before use. A
slice, for example, is a three-item descriptor containing a pointer to
the data (inside an array), the length, and the capacity; until those
items are initialized, the slice is \type{nil}. For slices, maps, and channels,
\key{make} initializes the internal data structure and prepares the value for
use.
\begin{lbar}[]
\key{make} returns initialized (non zero) \emph{values}.
\end{lbar}
For instance,
\lstinline{make([]int, 10, 100)}
allocates an array of 100 ints and then creates a slice structure with
length 10 and a capacity of 100 pointing at the first 10 elements of the
array. In contrast,
\lstinline{new([]int)} returns
a pointer to a newly allocated, zeroed slice structure, that is, a
pointer to a \type{nil} slice value.
These examples illustrate the difference between \key{new} and
\key{make}.
\begin{lstlisting}
var p *[]int = new([]int) |\coderemark{Allocates slice structure; \var{*p == nil}}|
|\coderemark{Rarely useful}|
var v []int = make([]int, 100) |\coderemark{\var{v} refers to a new array of 100 ints}|
var p *[]int = new([]int) |\coderemark{Unnecessarily complex}|
*p = make([]int, 100, 100)
v := make([]int, 100) |\coderemark{Idiomatic}|
\end{lstlisting}
Remember that \key{make} applies only to maps, slices and channels and does
not return a pointer. To obtain an explicit pointer allocate with
\key{new}.
\begin{lbar}[new allocates; make initializes]
The above two paragraphs can be summarized as:
\begin{itemize}
\item \lstinline{new(T)} returns \var{*T} pointing to a zeroed \var{T}
\item \lstinline{make(T)} returns an initialized \var{T}
\end{itemize}
And of course \lstinline{make} is only used for slices, maps and channels.
\end{lbar}
\subsection{Constructors and composite literals}
\label{sec:constructors and composite literals}
Sometimes the zero value isn't good enough and an initializing
constructor is necessary, as in this example taken from the package
\package{os}.
\begin{lstlisting}
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
\end{lstlisting}
There's a lot of boiler plate in there. We can simplify it using a
\first{composite literal}{literal!composite}, which is an expression that
creates a new instance each time it is evaluated.
\begin{lstlisting}
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := File{fd, name, nil, 0} |\coderemark{Create a new \type{File}}|
return &f |\coderemark{Return the address of \var{f}}|
}
\end{lstlisting}
It is OK to return the address of a local variable.
the storage associated with the variable survives after the function
returns.
In fact, taking the address of a composite literal allocates a
fresh instance each time it is evaluated, so we can combine these last
two lines.\footnote{Taking the address of a composite literal tells the
compiler to allocate it on the heap, not the stack.}
\begin{lstlisting}
return &File{fd, name, nil, 0}
\end{lstlisting}
The items (called \first{fields}{fields}) of a composite
literal are laid out in order and must all be
present. However, by labeling the elements explicitly as field:value
pairs, the initializers can appear in any order, with the missing ones
left as their respective zero values. Thus we could say
\begin{lstlisting}
return &File{fd: fd, name: name}
\end{lstlisting}
As a limiting case, if a composite literal contains no fields at all, it
creates a zero value for the type. The expressions
\lstinline{new(File)} and
\lstinline|&File{}| are equivalent.
Composite literals can also be created for arrays, slices, and maps,
with the field labels being indices or map keys as appropriate. In these
examples, the initializations work regardless of the values of
\var{Enone}, and \var{Einval}, as long as they are distinct.
\begin{lstlisting}
ar := [...]string {Enone: "no error", Einval: "invalid argument"}
sl := []string {Enone: "no error", Einval: "invalid argument"}
ma := map[int]string {Enone: "no error", Einval: "invalid argument"}
\end{lstlisting}
\section{Defining your own types}
\label{sec:defining your own}
Of course Go allows you to define new types, it does this
with the \first{\key{type}}{keyword!type} keyword:
\begin{lstlisting}
type foo int
\end{lstlisting}
Creates
a new type \lstinline{foo} which acts like an \lstinline{int}.
Creating more sophisticated types is done with the
\first{\key{struct}}{keyword!struct}
keyword.
An example would be when we want record somebody's name (\type{string})
and age (\type{int}) in a single structure and make it a new type:
\lstinputlisting[label=src:struct,caption=Structures]{src/struct.go}
\needspace{5\baselineskip}
Apropos, the output of \lstinline{fmt.Printf("%v\n", a)} is
\begin{display}
&\{Pete 42\}
\end{display}
That is nice!
Go knows how to print your structure. If you
only want to print one, or a few, fields of the structure you'll
need to use \verb|.<field name>|. For example to only print the name:
\begin{lstlisting}
fmt.Printf("%s", a.name) |\coderemark{\%s formats a string}|
\end{lstlisting}
%% add text if a is a pointer
\subsection{More on structure fields}
As said each item in a structure is called a \index{field}{field}.
A struct with no fields: \lstinline|struct {}|
Or one with four\footnote{Yes, four (4).} fields:
\begin{lstlisting}
struct {
x, y int
A *[]int
F func()
}
\end{lstlisting}
If you omit the name for a field, you create an
\first{anonymous field}{field!anonymous}, for instance:
\begin{lstlisting}
struct {
T1 |\coderemark{Field name is \var{T1}}|
*T2 |\coderemark{Field name is \var{T2}}|
P.T3 |\coderemark{Field name is \var{T3}}|
x, y int |\coderemark{Field names are \var{x} and \var{y}}|
}
\end{lstlisting}
Note that field names that start with a capital letter are exported, i.e. can be
set or read from other packages. Field names that start with a lowercase are private
to the current package. The same goes for functions defined in packages, see chapter
\ref{chap:packages} for the details.
\subsection{Methods}
\label{sec:methods}
If you create functions that work on your newly defined type, you can
take two routes:
\begin{enumerate}
\item Create a function that takes the type as an argument.
\begin{lstlisting}
func doSomething(in1 *NameAge, in2 int) { /* ... */ }
\end{lstlisting}
This is (you might have guessed) a \first{\emph{function call}}{function!call}.
\item Create a function that works on the type (see \emph{receiver} in
listing \ref{src:function definition}):
\begin{lstlisting}
func (in1 *NameAge) doSomething(in2 int) { /* ... */ }
\end{lstlisting}
This is a \first{\emph{method call}}{method call}, which can be
used as:
\begin{lstlisting}
var n *NameAge
n.doSomething(2)
\end{lstlisting}
\end{enumerate}
Whether to use a function or method is entirely up to the programmer, but
if you want to satisfy an interface (see the next chapter) you must use
methods. If no such requirement exists it is a matter of taste whether
to use functions or methods.
But keep the following in mind, this is quoted from \cite{go_spec}:
\begin{quote}
If \type{x} is
addressable and \lstinline{&x}'s method set contains \func{m},
\lstinline{x.m()} is shorthand for \mbox{\lstinline{(&x).m()}}.
\end{quote}
In the above case this means that the following is \emph{not} an
error:
\begin{lstlisting}
var n NameAge |\coderemark{Not a pointer}|
n.doSomething(2)
\end{lstlisting}
Here Go will search the method list for \var{n} of type \type{NameAge},
come up empty and will then \emph{also} search the method list for
the type \type{*NameAge} and will translate this call to
\lstinline{(&n).doSomething(2)}.
There is a subtle but major difference between the following type
declarations. Also see \cite[section~``Type Declarations'']{go_spec}.
Suppose we have:
\begin{lstlisting}
// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct { /* Mutex fields */ }
func (m *Mutex) Lock() { /* Lock implementation */ }
func (m *Mutex) Unlock() { /* Unlock implementation */ }
\end{lstlisting}
We now create two types in two different manners:
\begin{itemize}
\item \lstinline|type NewMutex Mutex|.
\item \lstinline|type PrintableMutex struct { Mutex }|.
\end{itemize}
Now \var{NewMutux} is equal to \var{Mutex}, but
is \emph{does not} have \emph{any} of the methods of \var{Mutex}. In other words
its method set is empty.
But \var{PrintableMutex} \emph{has} \first{\emph{inherited}}{methods!inherited} the
method set from \var{Mutex}.
In the words of \cite{go_spec}:
\begin{quote}
The method set of \var{*PrintableMutex} contains the methods
\func{Lock} and \func{Unlock} bound to its anonymous field \var{Mutex}.
\end{quote}
\section{Conversions}
\label{sec:conversions}
Sometimes you want to convert a type to another type.
This is possible in Go, but
there are some rules. For starters, converting from one value to another
is done by operators (that look like functions: \func{byte()}) and not all conversions are allowed.
\begin{table}[H]
\begin{center}
\caption[Valid conversions]{Valid conversions,
\lstinline{float64} works the same as \lstinline{float32}}
\label{tab:convesion}
\input{tab/conversion.tex}
\end{center}
\end{table}
\begin{itemize}
\item{
From a \lstinline{string} to a slice of bytes or runes.
\begin{lstlisting}
mystring := "hello this is string"
\end{lstlisting}
\begin{lstlisting}
byteslice := []byte(mystring)
\end{lstlisting}
Converts to a \type{byte} slice, each \type{byte} contains the integer value
of the corresponding byte in the string. Note that as strings in Go
are encoded in UTF-8 some characters in the string may end up in 1, 2, 3
or 4 bytes.
\begin{lstlisting}
runeslice := []rune(mystring)
\end{lstlisting}
Converts to an \type{rune} slice, each \type{rune} contains a Unicode code
point. Every character from the string corresponds to one rune.
}
\item{
From a slice of bytes or runes to a \lstinline{string}.
\begin{lstlisting}
b := []byte{'h','e','l','l','o'} |\coderemark{Composite literal}|
s := string(b)
i := []rune{257,1024,65}
r := string(i)
\end{lstlisting}
}
\end{itemize}
For numeric values the following conversions are defined:
\begin{itemize}
\item{Convert to a integer with a specific (bit) length:
\lstinline{uint8(int)};}
\item{From floating point to an integer value:
\lstinline{int(float32)}. This discards the fraction part
from the floating point value;}
\item{The other way around: \lstinline{float32(int)};}
\end{itemize}
\subsection{User defined types and conversions}
How can you convert between the types you have defined
yourself?
We create two types here \type{Foo} and \type{Bar}, where
\lstinline{Bar} is an alias for \type{Foo}:
\begin{lstlisting}
type foo struct { int } |\coderemark{Anonymous struct field}|
type bar foo |\coderemark{bar is an alias for foo}|
\end{lstlisting}
Then we:
\begin{lstlisting}
var b bar = bar{1} |\coderemark{Declare \var{b} to be a \type{bar}}|
var f foo = b |\coderemark{Assign \var{b} to \var{f}}|
\end{lstlisting}
Which fails on the last line with:
\noindent\error{cannot use b (type bar) as type foo in assignment}
\noindent{}This can be fixed with a conversion:
\begin{lstlisting}
var f foo = foo(b)
\end{lstlisting}
Note that converting structures that are not identical in their fields
is more difficult. Also note that converting \lstinline{b} to a plain
\type{int} also fails; an integer is not the same as a structure containing
an integer.
\section{Exercises}
\input{ex-beyond/ex-pointer-arith.tex}
\input{ex-beyond/ex-map.tex}
\input{ex-beyond/ex-pointers.tex}
\input{ex-beyond/ex-double-linked-list.tex}
\input{ex-beyond/ex-cat.tex}
\input{ex-beyond/ex-pointers-method.tex}
\cleardoublepage
\section{Answers}
\shipoutAnswer