-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions.tex
541 lines (414 loc) · 13.8 KB
/
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
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
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
\cleardoublepage
\phantomsection
\chapter{Functions}
\begin{quote}
\textit{Either mathematics is too big for the human mind, or the human mind is
more than a machine.} --- Kurt Gödel
\end{quote}
In this chapter, we are going to learn more about functions. You have
already seen functions in previous chapters. Functions provide a way
to group statements together and call it multiple times. If you don't
use functions, the same statements will be written again and again in
different parts of your code. Ultimately functions helps you to reuse
code. A function can optionally accept arguments and execute
statements and optionally return values.
Mathematical function would be a good analogy to understand the
concept of functions in programming. We have seen this mathematical
function in the Quick Start chapter.
\begin{figure}[h!]
\centering
\begin{tikzpicture}
\node at (1.7,0) {{\Large 3.14r}};
\node at (2.55,0.32) {{\Large 2}};
\node at (0,0) {{\Large f(r)}};
\node at (0.7,0) {{\Large =}};
\end{tikzpicture}
\caption{Mathematical function for area of a circle}
\end{figure}
This function square the input value and multiply with 3.14.
Depending on the input value the output varies.
\begin{figure}[h!]
\centering
\begin{tikzpicture}
\draw [thick, ->] (0,1) -- (2,1);
\node at (.5,1.2) {r};
\draw [thick] (2,0) rectangle (7,2);
\node at (4.5,1) {3.14r};
\node at (5.1,1.2) {2};
\node at (4.5,2.3) {f(r)};
\draw [thick, ->] (7,1) -- (9,1);
\node at (8.5,1.2) {y};
\end{tikzpicture}
\caption{Blackbox representation of a function}
\end{figure}
As you can see in the diagram, \texttt{r} is the input and \texttt{y}
is the output. A function in Go can take input arguments and perform
actions and return values. A minimal implementation of this function
in Go looks like this.
\begin{lstlisting}[numbers=none]
func Area(r float64) float64 {
return 3.14 * r * r
}
\end{lstlisting}
The function declaration starts with \texttt{func} keyword. In the
above example, \texttt{Area} is the function name which can be later
used to call the function. The arguments that can be received by this
function is given within brackets. After the input parameters you can
specify the output parameters. If there are more than one output
parameter required, use a bracket around that. After the output
parameters, add one opening curly bracket. The statements can be
written in the next line on wards until the closing curly bracket. It
is recommended to start a new line after the opening curly bracket and
closing bracket can be in a line by its own.
Here is a complete example with usage of the Area function.
\begin{lstlisting}
package main
import "fmt"
func Area(r float64) float64 {
return 3.14 * r * r
}
func main() {
area := Area(5.0)
fmt.Println(area)
}
\end{lstlisting}
In the above example, the \texttt{Area} function is called with
argument value as \texttt{5.0} (line number 10). And the short
variable declaration syntax is used to assign value returned by the
function. The type of the variable \texttt{area} will be
\texttt{float64} as the \texttt{Area} function returns with that type.
If you run the above program, you will get the output like this:
\begin{lstlisting}[numbers=none]
$ go run area.go
78.5
\end{lstlisting}
\section{Parameters}
A function can accept any number of arguments depending on the
parameters defined. The \texttt{Area} function in the previous
section accepts one argument.
If the function definition doesn't have any parameters, you cannot
pass any arguments. Parameter\index{parameter} is the variable used
in the declaration of a function. Where as
argument\index{parameter!argument} is the actual value of this
variable that gets passed to function. Consider this example:
\begin{lstlisting}
package main
import (
"fmt"
"time"
)
func TimeNow() string {
t := time.Now()
h := t.Hour()
m := t.Minute()
return fmt.Sprintf("%d:%d", h, m)
}
func main() {
now := TimeNow()
fmt.Println(now)
}
\end{lstlisting}
The \texttt{TimeNow} function doesn't declare any parameters. So,
when the function is called, no arguments are passed. If you try to
pass any arguments, you will get an error with this
message: \texttt{too many arguments in call to TimeNow}.
\subsection{More parameters}
A function can accepts more arguments of same or different types.
\begin{lstlisting}
package main
import "fmt"
func sum(a int, b int) int {
return a + b
}
func main() {
s := sum(5, 2)
fmt.Println(s)
}
\end{lstlisting}
The above \texttt{sum} function accepts two integer parameters. Since
both parameters are integers, the type can be specified once.
\begin{lstlisting}[numbers=none]
func sum(a, b int) int {
return a + b
}
\end{lstlisting}
\section{Return Values}
A function can return any number of values\index{return}. The calling
side should have comma separated variables to receive the return
values. If you are only interested in a particular return value, you
can use underscore as the variable name for others.
Here is an example function which return two values:
\begin{lstlisting}
package main
import "fmt"
func div(a, b int) (int, int) {
return a / b, a % b
}
func main() {
v, r := div(5, 2)
fmt.Println(v, r)
}
\end{lstlisting}
In the above example, the div function return two values. So two
variables are used to assign the values. If you use one variable it
will produce compile time error. The compile time error will be
produced, if more than two variables are used to assigned. However,
it is possible to call the function without assigning to any
variables.
\begin{lstlisting}[numbers=none]
v, _ := div(5, 2)
div(5, 2)
\end{lstlisting}
By convention, the last return value will be an error value. Here is
a modified example.
\begin{lstlisting}[numbers=none]
func div(a, b int) (int, int, error) {
if b == 0 {
err := errors.New("Zero division error")
return 0, 0, err
}
return a / b, a % b, nil
}
\end{lstlisting}
In the above example, package \texttt{errors} is used to create a new
error value. If there is no error, a \texttt{nil} value can be
returned.
\subsection{Named output parameters}
It is possible to specify name for output
parameters\index{return!named parameter}. These variables can be used
to assign values. With named output parameters, return statement need
not to explicitly specify the variables.
\begin{lstlisting}
package main
import "fmt"
func div(a, b int) (int d, int r) {
d := a / b
r := a % b
return
}
func main() {
v, r := div(5, 2)
fmt.Println(v, r)
}
\end{lstlisting}
\section{Variadic Functions}
A function\index{function!variadic}\index{variadic function} which can
receive any number of arguments of a particular type is called
variadic function. Variable name along with an ellipsis
(\texttt{...}) symbol is used to declare variadic parameters.
The \texttt{fmt.Println} is a commonly used variadic function.
Here is a complete example:
\begin{lstlisting}
package main
import "fmt"
func sum(nums ...int) {
fmt.Printf("%#v ", nums)
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2)
sum(1, 2, 3)
nums := []int{1, 2, 3, 4}
sum(nums...)
}
\end{lstlisting}
If you run the above program, this will be the output:
\begin{lstlisting}[numbers=none]
$ go run variadic.go
[]int{1, 2} Sum: 3
[]int{1, 2, 3} Sum: 6
[]int{1, 2, 3, 4} Sum: 10
\end{lstlisting}
As you can see the arguments are captured into a slice. You can send
values in a slice to a variadic function using the ellipsis syntax as
a suffix.
\section{Anonymous Functions}
It is possible to declare a function without a
name\index{function!anonymous}. These type of functions can be used
to create function closures. A closure is an anonymous function that
access variables from outside its body.
\begin{lstlisting}
package main
import "fmt"
func main() {
name := "Tom"
func() {
fmt.Println("Hello", name)
}()
}
\end{lstlisting}
\section{Function as Value}
Function is a first class citizen\index{function!value} in Go, so it
can be passed as an argument and return as a value.
\begin{lstlisting}
package main
import "fmt"
func Greeting(msg string) func(name string) string {
}
func main() {
name := "Tom"
func() {
fmt.Println("Hello", name)
}()
}
\end{lstlisting}
\section{Methods}
\label{sec:methods}
A function can be associated with a type, that is called method.
Additional methods can be added to types defined locally. However,
adding additional methods for non-local type is not allowed. Here is
an example program:
\begin{lstlisting}[numbers=none]
package main
import (
"fmt"
"os"
"strconv"
)
type Number int
func (num Number) Even() bool {
if num%2 == 0 {
return true
} else {
return false
}
}
func main() {
i := os.Args[1]
n, err := strconv.Atoi(i)
if err != nil {
fmt.Println("Not a number:", i)
os.Exit(1)
}
num := Number(n)
fmt.Println(num.Even())
}
\end{lstlisting}
In the above program, a custom type named \texttt{Number} is
defined. Later a method named \texttt{Even} is defined below. To
define a method for any type, the syntax is like this: \texttt{func
(value CustomType) MethodName()}. You can also define input
parameters and output parameters. In the above the output parameter
is given as a \texttt{bool} value.
You can associate methods\index{method} to structs. Consider this
struct:
\begin{lstlisting}[numbers=none]
type Rectangle struct {
Width float64
Height float64
}
\end{lstlisting}
If you want methods to calculate area and perimeter for this rectangle,
you can define methods like this:
\begin{lstlisting}[numbers=none]
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width * r.Height)
}
\end{lstlisting}
You can call these methods from the struct initialized using
the \texttt{Rectangle} struct. Here is an example:
\begin{lstlisting}[numbers=none]
r := Rectangle{3.0, 5.0}
area := r.Area()
perimeter := r.Perimeter()
\end{lstlisting}
When a function is bound to a type, it is called method\index{method}.
The type that is bound is called receiver. A receiver could be any
type with a name. When you declare a method, it is defined using
receiver argument. The receiver argument points to the type where the
method will be available. The receiver argument is specified between
func keyword and the method name inside a bracket with a name.
Methods can be defined only on types declared in the same package.
Declaring a method on built-in type is also illegal.
Here is an example:
\begin{lstlisting}
package main
import "fmt"
type Circle struct {
radius float64
}
func (c Circle) Area() float64 {
return 3.14 * c.radius * c.radius
}
func main() {
c := Circle{3.4}
a := c.Area()
fmt.Println(a)
}
\end{lstlisting}
In the above example, the method \texttt{Area} calculate area for a
circle.
The receiver could be pointer also. Here is a modified example with
pointer receiver:
\lstinputlisting{code/functions/pointer1.go}
In the above example, the \texttt{Area} method is using a pointer
receiver. When creating object, you can create a normal value or a
pointer value. Calling the \texttt{Area} can use either a normal
value or a pointer value.
Pointer receiver\index{pointer!receiver} can be used when for any of
these three reason:
\begin{itemize}
\item To modify the receiver itself by changing the value of attributes.
\item The object is very large and a passing a deep copy is expensive.
\item Consistency: Let all methods have pointer receivers.
\end{itemize}
You can use new function to allocate memory for \textit{struct}:
\begin{lstlisting}[numbers=none]
type Temperature struct{
Value float64
}
name := new(Temperature)
\end{lstlisting}
In the above example, the zero value is allocated and assigned to the
variable \texttt{name}. But in some cases, zero value is not what you
required. So you can use \texttt{\&} to with struct syntax like this:
\begin{lstlisting}[numbers=none]
type Temperature struct{
Value float64
}
name := &Temperature{Value: -7.6}
\end{lstlisting}
As you can see, the temperature value is set to \texttt{-7.6} and
assigned to the variable.
\section{Exercises}
\textbf{Exercise 1:} Write a method to calculate the area of a rectangle for a
given struct with width and height.
\textbf{Solution:}
\begin{lstlisting}[numbers=none]
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
\end{lstlisting}
\subsection{Additional Exercises}
Answers to these additional exercises are given in the Appendix A.
\textbf{Problem 1:} Write a program with a function to calculate the perimeter of a circle.
\section*{Summary}
This chapter explained the main features of functions in Go. It covered how to
send input parameters and receive return values. It also explained about
variadic functions and anonymous functions. This chapter briefly covered
methods. The next chapter will cover interfaces. Along with that, we will learn
more about methods.
Brief summary of key concepts introduced in this chapter:
\begin{itemize}
\item Functions are used to group together related code and make it easier to read and
understand. They can also be used to reuse code in different parts of a
program.
\item Input parameters are values that are passed into a function when it is called.
Return values are values that are returned by a function when it finishes
executing.
\item Variadic functions are functions that can accept a variable number of input
parameters. Anonymous functions are functions that are defined without a name.
\item Methods are functions that are associated with a specific type. They can be used
to operate on objects of that type.
\end{itemize}