This repository has been archived by the owner on Mar 22, 2021. It is now read-only.
/
go-functions.tex
357 lines (322 loc) · 11.5 KB
/
go-functions.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
\epi{I'm always delighted by the light touch and stillness of
early programming languages. Not much text; a lot gets
done. Old programs read like quiet conversations
between a well-spoken research worker and a well-
studied mechanical colleague, not as a debate with a
compiler. Who'd have guessed sophistication bought
such noise?}{\textsc{RICHARD P. GABRIEL}}
\noindent{}Functions are the basic building blocks in Go programs; all interesting
stuff happens in them. A function is declared as follows:
\input{fig/function.tex}
\showremarks
Here are a two examples, the first is a function without a return value,
the second is a simple function that returns its input.
\begin{lstlisting}
func subroutine(in int) {
return
}
\end{lstlisting}
\begin{lstlisting}
func identity(in int) int {
return in
}
\end{lstlisting}
Functions can be declared in any order you wish, the compiler scans the
entire file before execution. So function prototyping is a thing of the
past in Go.
Go disallows nested functions.
You can however
work around this by using anonymous functions, see section
"\titleref{sec:functions as values}" on page \pageref{sec:functions as values}
in this chapter.
\todo{types in function, a nono. Maybe in package chapter.}
\section{Scope}
Variables declared outside any functions are \first{global}{scope!local} in Go, those
defined in functions are \first{local}{scope!local} to those functions. If names overlap --- a
local variable is declared with the same name as a global one --- the
local variable hides the global one when the current function is
executed.
\begin{minipage}{.5\textwidth}
\input{fig/scope1.tex}
\hfill
\vfill
\end{minipage}
\hfill
\begin{minipage}{.5\textwidth}
\input{fig/scope2.tex}
\hfill
\vfill
\end{minipage}
In listing \ref{src:scope1} we introduce a local variable \var{a}
in the function \func{q()}.
This local \var{a} is only visible in \func{q()}. That is
why the code will print: \texttt{656}.
In listing \ref{src:scope2} no new variables are introduced, there
is only a global \var{a}.
Assigning a new value to will be globally visible. This code will
print: \texttt{655}
In the following example we call \func{g()} from \func{f()}:
\lstinputlisting[caption=Scope when calling functions from functions]{src/scope3.go}
The printout will be: \texttt{565}. A \emph{local} variable is only
valid when we are executing the function in which it is defined.
%%Finally, one can create a \first{"function literal"}{function literal} in which you essentially
%%define a function inside another
%%function, i.e. a \first{nested function}{nested function}.
%%The following figure should clarify why it prints: \texttt{565757}.
%%\input{fig/scope3.tex}
\section{Multiple return values}
\label{sec:multiple return}
One of Go's unusual features is that functions and methods can return multiple
values (Python can do this too). This can be used to improve on a couple of
clumsy idioms in C programs:
in-band error returns (such as -1 for \texttt{EOF}) and modifying an argument.
In C, a write error is signaled by a negative count with the error code
secreted away in a volatile location. In Go, \lstinline{Write} returns a count and an
error: "Yes, you wrote some bytes but not all of them because you filled the
device". The signature of \lstinline{*File.Write} in package
\package{os} is:
\begin{lstlisting}
func (file *File) Write(b []byte) (n int, err Error)
\end{lstlisting}
and as the documentation says, it returns the number of bytes written and a
non-\lstinline{nil} \var{Error} when \lstinline{n != len(b)}. This is a common
style in Go.
A similar approach obviates the need to pass a pointer to a return value to
simulate a reference parameter. Here's a simple-minded function to grab a
number from a position in a byte array, returning the number and the next
position.
\begin{lstlisting}
func nextInt(b []byte, i int) (int, int) {
x := 0
// Naively assume everything is a number
for ; i < len(b); i++ {
x = x*10 + int(b[i])-'0'
}
return x, i
}
\end{lstlisting}
You could use it to scan the numbers in an input array a like this:
\begin{lstlisting}
a := []byte{'1', '2', '3', '4'}
var x int
for i := 0; i < len(a); { |\coderemark{No \texttt{i++}}|
x, i = nextInt(a, i)
println(x)
}
\end{lstlisting}
Without having tuples as a native type, multiple return values is the next
best thing to have. You can return precisely what you want without
overloading the domain space with special values to signal errors.
\section{Named result parameters}
\label{sec:named result parameters}
The return or result parameters of a Go function can be given names and used
as regular variables, just like the incoming parameters. When named, they are
initialized to the zero values for their types when the function begins; if the
function executes a \key{return} statement with no arguments, the current values of
the result parameters are used as the returned values. Using this
features enables you (again) to do more with less code \footnote{This is
a motto of Go; "Do \emph{more} with \emph{less} code".}.
The names are not mandatory but they can make code shorter and clearer:
\emph{they are documentation}.
If we name the results of \lstinline{nextInt} it becomes obvious which
returned \type{int} is which.
\begin{lstlisting}
func nextInt(b []byte, pos int) (value, nextPos int) { /* ... */ }
\end{lstlisting}
Because named results are initialized and tied to an unadorned
\key{return},
they can simplify as well as clarify. Here's a version of
\lstinline{io.ReadFull} that uses them well:
\begin{lstlisting}
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:len(buf)]
}
return
}
\end{lstlisting}
In the following example we declare a simple function which calculates
\gomarginpar{Some text in this section comes from \cite{go_intro}.} % layout
the factorial value of a value \var{x}.
\begin{lstlisting}
func Factorial(x int) int { |\coderemark{\texttt{func Factorial(x int) (int)} is also OK}|
if x == 0 {
return 1
} else {
return x * Factorial(x - 1)
}
}
\end{lstlisting}
So you could also write factorial as:
\begin{lstlisting}
func Factorial(x int) (result int) {
if x == 0 {
result = 1
} else {
result = x * Factorial(x - 1)
}
return
}
\end{lstlisting}
When we use named result values, the code is shorter and
easier to read.
You can also write a function with multiple return values:
\begin{lstlisting}
func fib(n) (val int, pos int) {
if n == 0 {
val = 1
pos = 0
} else if n == 1 {
val = 1
pos = 1
} else {
v1, _ := fib(n-1)
v2, _ := fib(n-2)
val = v1 + v2
pos = n
}
return
}
\end{lstlisting}
\section{Deferred code}
Suppose you have a function in which you open a file and perform various
writes and reads on it. In such a function there are often spots where
you want to return early. If you do that, you will need to close the file
descriptor you are working on. This often leads to the following code:
\begin{lstlisting}[caption=Without \func{defer}]
func ReadWrite() bool {
file.Open("file")
// Do you thing
if failureX {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
}
\end{lstlisting}
Here a lot of code is repeated. To overcome this ---
and do more in less code --- Go has the
\first{\key{defer}}{keyword!defer} statement. After
\key{defer} you specify a function which is called just \emph{before} a
\key{return} from the function is executed.
The code above could be rewritten as follows. This makes the
function more readable, shorter and puts the \func{Close} right next
to the \func{Open}.
\begin{lstlisting}[caption=With \func{defer}]
func ReadWrite() bool {
file.Open("file")
defer file.Close() |\coderemark{\func{file.Close()} \emph{is} the function}|
// Do you thing
if failureX {
return false |\coderemark{\func{Close()} is now done automatically}|
}
if failureY {
return false |\coderemark{And here too}|
}
return true
}
\end{lstlisting}
You can put multiple functions on the "deferred list"\index{deferred list}, like this
example from \cite{effective_go}:
\begin{lstlisting}
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
\end{lstlisting}
Deferred functions are executed in LIFO order, so the above code
prints: \lstinline{4 3 2 1 0}.
\todo{Rob Pike: Closures are just local functions}
%% Rob Pike: Closures are just local functions
%%func Compose(f, g func(x float64) float64)
%%func(x float64) float64 {
%%return func(x float64) float64 {
%%return f(g(x))
%%}
%%}
%%func main() {
%%print(Compose(sin, cos)(0.5))
%%}
With \func{defer} you can even change return values, provided that
you are using named result parameters and a function
literal\index{function!literal}, i.e:
\begin{lstlisting}[caption=Function literal]
defer func() {
/* ... */
}() |\coderemark{() is needed here}|
\end{lstlisting}
In that (unnamed) function you can access any named return
parameter:
\begin{lstlisting}[caption=Access return values within \func{defer}]
func f() (ret int) { |\coderemark{\var{ret} is initialized with zero}|
defer func() {
ret++ |\coderemark{Increment \var{ret} with 1}|
}()
return 0 |\coderemark{1 \emph{not} 0 will be returned!}|
}
\end{lstlisting}
\section{Variadic parameters}
\todo{Extend this section a bit. How to call another function with
a variadic argument (propagation).}
Functions that take variadic parameters are functions that have a
variable number of parameters. To do this, you first
need to declare your function to take variadic arguments:
\begin{lstlisting}[caption=Variadac function declaration]
func myfunc(arg ... int) {}
\end{lstlisting}
The \lstinline{arg ... int} instructs Go to see this as a function that
takes a variable number of arguments. Note that these arguments all
have the type \type{int}. Inside your function's body the variable
\var{arg} is a slice of ints:
\begin{lstlisting}
for _, n := range arg {
fmt.Printf("And the number is: %d\n", n)
}
\end{lstlisting}
If you don't specify the type of the variadic argument it defaults to the
empty interface \var{interface\{\}} (see chapter
\ref{chap:interfaces}").
\section{Functions as values}
\label{sec:functions as values}
\index{function!as values}
\index{function!literals}
As with almost everything in Go, functions are also \emph{just} values.
They can be assigned to variables as follows:
\lstinputlisting[label=src:anonfunc,caption=Anonymous function]{src/anon-func.go}
If we use \lstinline{fmt.Printf("%T\n", a)} to print the type of
\var{a}, it prints \func{func()}.
Functions--as--values may also be used in other places, like in maps.
Here we convert from integers to functions:
\begin{lstlisting}[caption=Functions as values in maps]
var xs = map[int]func() int{
1: func() int { return 10 },
2: func() int { return 20 },
3: func() int { return 30 }, |\coderemark{Mandatory ,}|
/* ... */
}
\end{lstlisting}
Or you can write a function that takes a function as its parameter, for
example a \func{Map} function that works on \type{int} slices. This is
left as an exercise for the reader, see exercise Q\ref{ex:map function}
on page \pageref{ex:map function}.
\section{Panic and recovering}
\label{sec:panic}
\cite{go_blog_panic}
\todo{}
\section{Exercises}
\input{ex-functions/ex-order.tex}
\input{ex-functions/ex-scope.tex}
\input{ex-functions/ex-stack.tex}
\input{ex-functions/ex-vararg.tex}
\input{ex-functions/ex-fib.tex}
\input{ex-functions/ex-map.tex}
\cleardoublepage
\section{Answers}
\shipoutAnswer