Skip to content

Instantly share code, notes, and snippets.

@miekg
Last active September 3, 2015 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miekg/0251f3e28652fa603a51 to your computer and use it in GitHub Desktop.
Save miekg/0251f3e28652fa603a51 to your computer and use it in GitHub Desktop.
"Learning Go" in Internet Draft text format
Go R. Gieben
Internet-Draft January 7, 2015
Intended status: Standards Track
Expires: July 11, 2015
Learning Go
learning-go.md
Abstract
The source of this book [1] is written in mmark [2] and is converted
from the original LaTeX source [3].
_All example code used in this book is hereby put in the public
domain._
This work is licensed under the Attribution-NonCommercial-
ShareAlike 3.0 Unported License. To view a copy of this license,
visit <http://creativecommons.org/licenses/by-nc-sa/3.0/> or send
a letter to Creative Commons, 171 Second Street, Suite 300, San
Francisco, California, 94105, USA.
The following people made large or small contributions to earlier
versions of this book:
Adam J. Gray, Alexander Katasonov, Alexey Chernenkov, Alex Sychev,
Andrea Spadaccini, Andrey Mirtchovski, Anthony Magro, Babu Sreekanth,
Ben Bullock, Bob Cunningham, Brian Fallik, Cecil New, Cobold, Damian
Gryski, Daniele Pala, Dan Kortschak, David Otton, Fabian Becker,
Filip Zaludek, Hadi Amiri, Haiping Fan, Iaroslav Tymchenko, Jaap
Akkerhuis, JC van Winkel, Jeroen Bulten, Jinpu Hu, John Shahid,
Jonathan Kans, Joshua Stein, Makoto Inoue, Marco Ynema, Mayuresh
Kathe, Mem, Michael Stapelberg, Nicolas Kaiser, Olexandr Shalakhin,
Paulo Pinto, Peter Kleiweg, Philipp Schmidt, Robert Johnson, Russel
Winder, Simoc, Sonia Keys, Stefan Schroeder, Thomas Kapplet, T.J.
Yang, Uriel\dagger, Vrai Stacey, Xing Xing.
"Learning Go" has been translated into (note that this used the
original LaTeX source).
o Chinese, by Xing Xing,
&#36825;&#37324;&#26159;&#20013;&#25991;&#35793;&#26412;:
<http://www.mikespook.com/learning-go/>
I hope this book is useful.
Miek Gieben, London, 2015.
Gieben Expires July 11, 2015 [Page 1]
Internet-Draft Learning Go January 2015
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on July 11, 2015.
Copyright Notice
Copyright (c) 2015 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License.
Table of Contents
1. Learning Go . . . . . . . . . . . . . . . . . . . . . . . . . 5
2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1. How to Read this Book . . . . . . . . . . . . . . . . . . 7
2.2. Official Documentation . . . . . . . . . . . . . . . . . 7
3. Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1. Hello World . . . . . . . . . . . . . . . . . . . . . . . 8
3.2. Compiling and Running Code . . . . . . . . . . . . . . . 9
3.3. Variables, Types and Keywords . . . . . . . . . . . . . . 9
3.3.1. Boolean Types . . . . . . . . . . . . . . . . . . . . 10
3.3.2. Numerical Types . . . . . . . . . . . . . . . . . . . 11
3.3.3. Constants . . . . . . . . . . . . . . . . . . . . . . 11
3.3.4. Strings . . . . . . . . . . . . . . . . . . . . . . . 12
3.3.5. Runes . . . . . . . . . . . . . . . . . . . . . . . . 12
3.3.6. Complex Numbers . . . . . . . . . . . . . . . . . . . 13
Gieben Expires July 11, 2015 [Page 2]
Internet-Draft Learning Go January 2015
3.3.7. Errors . . . . . . . . . . . . . . . . . . . . . . . 13
3.4. Operators and Built-in Functions . . . . . . . . . . . . 13
3.5. Go Keywords . . . . . . . . . . . . . . . . . . . . . . . 14
3.6. Control Structures . . . . . . . . . . . . . . . . . . . 14
3.6.1. If-Else . . . . . . . . . . . . . . . . . . . . . . . 15
3.6.2. Goto . . . . . . . . . . . . . . . . . . . . . . . . 15
3.6.3. For . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.6.4. Break and Continue . . . . . . . . . . . . . . . . . 16
3.6.5. Range . . . . . . . . . . . . . . . . . . . . . . . . 17
3.6.6. Switch . . . . . . . . . . . . . . . . . . . . . . . 18
3.7. Built-in Functions . . . . . . . . . . . . . . . . . . . 19
3.8. Arrays, Slices, and Maps . . . . . . . . . . . . . . . . 20
3.8.1. Arrays . . . . . . . . . . . . . . . . . . . . . . . 20
3.8.2. Slices . . . . . . . . . . . . . . . . . . . . . . . 20
3.8.3. Maps . . . . . . . . . . . . . . . . . . . . . . . . 23
3.9. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 24
3.9.1. For-loop . . . . . . . . . . . . . . . . . . . . . . 24
3.9.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 24
3.9.3. Average . . . . . . . . . . . . . . . . . . . . . . . 26
3.9.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 26
3.9.5. FizzBuzz . . . . . . . . . . . . . . . . . . . . . . 26
3.9.6. Answer . . . . . . . . . . . . . . . . . . . . . . . 26
4. Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.1. Scope . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.2. Functions as values . . . . . . . . . . . . . . . . . . . 30
4.3. Callbacks . . . . . . . . . . . . . . . . . . . . . . . . 30
4.4. Deferred Code . . . . . . . . . . . . . . . . . . . . . . 31
4.5. Variadic Parameter . . . . . . . . . . . . . . . . . . . 33
4.6. Panic and recovering . . . . . . . . . . . . . . . . . . 34
4.7. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 35
4.7.1. Average . . . . . . . . . . . . . . . . . . . . . . . 35
4.7.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 35
4.7.3. Bubble sort . . . . . . . . . . . . . . . . . . . . . 36
4.7.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 36
4.7.5. For-loop II . . . . . . . . . . . . . . . . . . . . . 37
4.7.6. Answer . . . . . . . . . . . . . . . . . . . . . . . 37
4.7.7. Fibonacci . . . . . . . . . . . . . . . . . . . . . . 37
4.7.8. Answer . . . . . . . . . . . . . . . . . . . . . . . 38
4.7.9. Var args . . . . . . . . . . . . . . . . . . . . . . 38
4.7.10. Answer . . . . . . . . . . . . . . . . . . . . . . . 38
4.7.11. Functions that return functions . . . . . . . . . . . 39
4.7.12. Answer . . . . . . . . . . . . . . . . . . . . . . . 39
4.7.13. Minimum . . . . . . . . . . . . . . . . . . . . . . . 40
4.7.14. Answer . . . . . . . . . . . . . . . . . . . . . . . 40
4.7.15. Map function . . . . . . . . . . . . . . . . . . . . 40
4.7.16. Answer . . . . . . . . . . . . . . . . . . . . . . . 40
4.7.17. Stack . . . . . . . . . . . . . . . . . . . . . . . . 41
4.7.18. Answer . . . . . . . . . . . . . . . . . . . . . . . 41
Gieben Expires July 11, 2015 [Page 3]
Internet-Draft Learning Go January 2015
5. Packages . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.1. Identifiers . . . . . . . . . . . . . . . . . . . . . . . 45
5.2. Documenting packages . . . . . . . . . . . . . . . . . . 46
5.3. Testing packages . . . . . . . . . . . . . . . . . . . . 47
5.4. Useful packages . . . . . . . . . . . . . . . . . . . . . 49
5.5. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 50
5.5.1. Stack as package . . . . . . . . . . . . . . . . . . 50
5.5.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 51
5.5.3. Calculator . . . . . . . . . . . . . . . . . . . . . 52
5.5.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 52
6. Beyond the basics . . . . . . . . . . . . . . . . . . . . . . 53
6.1. Allocation . . . . . . . . . . . . . . . . . . . . . . . 54
6.1.1. Allocation with new . . . . . . . . . . . . . . . . . 54
6.1.2. Allocation with make . . . . . . . . . . . . . . . . 55
6.1.3. Constructors and composite literals . . . . . . . . . 56
6.2. Defining your own types . . . . . . . . . . . . . . . . . 57
6.2.1. More on structure fields . . . . . . . . . . . . . . 58
6.2.2. Methods . . . . . . . . . . . . . . . . . . . . . . . 58
6.3. Conversions . . . . . . . . . . . . . . . . . . . . . . . 59
6.3.1. User defined types and conversions . . . . . . . . . 61
6.4. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 61
6.4.1. Map function with interfaces . . . . . . . . . . . . 61
6.4.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 61
6.4.3. Pointers . . . . . . . . . . . . . . . . . . . . . . 62
6.4.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 63
6.4.5. Linked List . . . . . . . . . . . . . . . . . . . . . 63
6.4.6. Answer . . . . . . . . . . . . . . . . . . . . . . . 63
6.4.7. Cat . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.4.8. Answer . . . . . . . . . . . . . . . . . . . . . . . 66
6.4.9. Method calls . . . . . . . . . . . . . . . . . . . . 70
6.4.10. Answer . . . . . . . . . . . . . . . . . . . . . . . 70
7. Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1. Which is what? . . . . . . . . . . . . . . . . . . . . . 72
7.2. Empty interface . . . . . . . . . . . . . . . . . . . . . 73
7.3. Methods . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.4. Methods on interface types . . . . . . . . . . . . . . . 74
7.5. Interface names . . . . . . . . . . . . . . . . . . . . . 75
7.6. A sorting example . . . . . . . . . . . . . . . . . . . . 75
7.7. Listing interfaces in interfaces . . . . . . . . . . . . 77
7.8. Introspection and reflection . . . . . . . . . . . . . . 78
7.9. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 80
7.9.1. Interfaces and max() . . . . . . . . . . . . . . . . 80
7.9.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 81
7.9.3. Pointers and reflection . . . . . . . . . . . . . . . 81
7.9.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 82
8. Concurrency . . . . . . . . . . . . . . . . . . . . . . . . . 82
8.1. Make it run in parallel . . . . . . . . . . . . . . . . . 85
8.2. More on channels . . . . . . . . . . . . . . . . . . . . 85
Gieben Expires July 11, 2015 [Page 4]
Internet-Draft Learning Go January 2015
8.3. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 86
8.3.1. Channels . . . . . . . . . . . . . . . . . . . . . . 86
8.3.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 86
8.3.3. Fibonacci II . . . . . . . . . . . . . . . . . . . . 87
8.3.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 87
9. Communication . . . . . . . . . . . . . . . . . . . . . . . . 88
9.1. io.Reader . . . . . . . . . . . . . . . . . . . . . . . . 90
9.2. Some examples . . . . . . . . . . . . . . . . . . . . . . 91
9.3. Command line arguments . . . . . . . . . . . . . . . . . 91
9.4. Executing commands . . . . . . . . . . . . . . . . . . . 92
9.5. Networking . . . . . . . . . . . . . . . . . . . . . . . 92
9.6. Exercises . . . . . . . . . . . . . . . . . . . . . . . . 93
9.6.1. Finger daemon . . . . . . . . . . . . . . . . . . . . 93
9.6.2. Answer . . . . . . . . . . . . . . . . . . . . . . . 94
9.6.3. Echo server . . . . . . . . . . . . . . . . . . . . . 95
9.6.4. Answer . . . . . . . . . . . . . . . . . . . . . . . 95
9.6.5. Answer . . . . . . . . . . . . . . . . . . . . . . . 97
9.6.6. Uniq . . . . . . . . . . . . . . . . . . . . . . . . 98
9.6.7. Answer . . . . . . . . . . . . . . . . . . . . . . . 98
9.6.8. Quine . . . . . . . . . . . . . . . . . . . . . . . . 98
9.6.9. Answer . . . . . . . . . . . . . . . . . . . . . . . 99
9.6.10. Processes . . . . . . . . . . . . . . . . . . . . . . 99
9.6.11. Answer . . . . . . . . . . . . . . . . . . . . . . . 100
9.6.12. Number cruncher . . . . . . . . . . . . . . . . . . . 101
9.6.13. Answer . . . . . . . . . . . . . . . . . . . . . . . 102
10. References . . . . . . . . . . . . . . . . . . . . . . . . . 105
10.1. Informative References . . . . . . . . . . . . . . . . . 105
10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 110
1. Learning Go
<fig/bumper-inverse.png>
2. Introduction
Is Go an object-oriented language? Yes and no.
-- Frequently asked questions, Go Authors
The Go programming language is an open source project language to
make programmers more productive.
According to the website [go_web] "Go is expressive, concise, clean,
and efficient". And indeed it is. My initial interest was piqued
when I read early announcements about this new language that had
built-in concurreny and a C-like syntax (Erlang also has built-in
Gieben Expires July 11, 2015 [Page 5]
Internet-Draft Learning Go January 2015
concurrency, but I could never get used to its syntax). Go is a
compiled statically typed language that feels like a dynamically
typed, interpreted language. My go to (scripting!) language Perl has
taken a back seat now that Go is around.
The unique Go language is defined by these principles:
Clean and Simple Go strives to keep things small and beautiful. You
should be able to do a lot in only a few lines of code.
Concurrent Go makes it easy to "fire off" functions to be run as
_very_ lightweight threads. These threads are called goroutines
in Go.
Channels Communication with these goroutines is done, either via
shared state or via channels [csp].
Fast Compilation is fast and execution is fast. The aim is to be as
fast as C. Compilation time is measured in seconds.
Safe Explicit casting and strict rules when converting one type to
another. Go has garbage collection. No more "free()" in Go: the
language takes care of this.
Standard format A Go program can be formatted in (almost) any way
the programmers want, but an official format exists. The rule is
very simple: The output of the filter "gofmt" _is the officially
endorsed format_.
Postfix types Types are given _after_ the variable name, thus "var a
int", instead of "int a".
UTF-8 UTF-8 is everywhere, in strings _and_ in the program code.
Finally you can use \Phi = \Phi + 1 in your source code.
Open Source The Go license is completely open source.
Fun Programming with Go should be fun!
As I mentioned Erlang also shares some features of Go. A notable
difference between Erlang and Go is that Erlang borders on being a
functional language, while Go is imperative. And Erlang runs in a
virtual machine, while Go is compiled.
Gieben Expires July 11, 2015 [Page 6]
Internet-Draft Learning Go January 2015
2.1. How to Read this Book
I've written this book for people who already know some programming
languages and how to program. In order to use this book, you (of
course) need Go installed on your system, but you can easily try
examples online in the Go playground. All exercises in this book
work with Go 1, the first stable release of Go -- if not, it's a bug.
The best way to learn Go is to create your own programs. Each
chapter therefore includes exercises (and answers to exercises) to
acquaint you with the language. Each exercise is either _easy_,
_intermediate_, or _difficult_. The answers are included after the
exercises on a new page. Some exercises don't have an answer; these
are marked with an asterisk.
Here's what you can expect from each chapter:
We'll look at the basic types, variables, and control structures
available in the language.
Here we look at functions, the basic building blocks of Go
programs.
We'll see that functions and data can be grouped together in
packages. We'll also see how to document and test our packages.
We'll create our own types. We'll also look at memory allocations
in Go.
We'll learn how to use interfaces. Interfaces are the central
concept in Go, as Go does not support object orientation in the
traditional sense.
We'll learn the "go" keyword, which can be used to start function
in separate routines (called goroutines). Communication with
those goroutines is done via channels.
Finally we'll see how to interface with the rest of the world from
within a Go program. We'll see how to create files and read and
write to and from them. We'll also briefly look into networking.
2.2. Official Documentation
There is a substantial amount of documentation written about Go. The
Go Tutorial [go_tutorial], the Go Tour (with lots of exercises) and
the Effective Go [effective_go] are helpful resources. The website
<http://golang.org/doc/> is a very good starting point for reading up
Gieben Expires July 11, 2015 [Page 7]
Internet-Draft Learning Go January 2015
on Go. Reading these documents is certainly not required, but it is
recommended.
When searching on the internet use the term "golang" instead of
plain "go".
Go comes with its own documentation in the form of a program called
"godoc". If you are interested in the documentation for the built-
ins, simply do this:
% godoc builtin
To get the documentation of the "hash" package, just:
% godoc hash
To read the documentation of "fnv" contained in "hash", you'll need
to issue "godoc hash/fnv" as "fnv" is a subdirectory of "hash".
PACKAGE DOCUMENTATION
package fnv
import "hash/fnv"
Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash
...
3. Basics
I am interested in this and hope to do something.
-- On adding complex numbers to Go, Ken Thompson
In this chapter we will look at the basic building blocks of the Go
programming language.
3.1. Hello World
In the Go tutorial, you get started with Go in the typical manner:
printing "Hello World" (Ken Thompson and Dennis Ritchie started this
when they presented the C language in the 1970s). That's a great way
to start, so here it is, "Hello World" in Go.
Gieben Expires July 11, 2015 [Page 8]
Internet-Draft Learning Go January 2015
package main <1>
import "fmt" <2> Implements formatted I/O.
/* Print something */ <3>
func main() { <4>
fmt.Printf("Hello, world.") <5>
}
Lets look at the program line by line. This first line is just
required (1). All Go files start with "package <something>", and
"package main" is required for a standalone executable.
"import "fmt"" says we need "fmt" in addition to "main" (2). A
package other than "main" is commonly called a library, a familiar
concept in many programming languages (see Section 5). The line ends
with a comment that begins with "//".
Next we another comment, but this one is enclosed in "/*" "*/" (3).
When your Go program is executed, the first function called will be
"main.main()", which mimics the behavior from C. Here we declare
that function (4).
Finally we call a function from the package "fmt" to print a string
to the screen. The string is enclosed with """ and may contain non-
ASCII characters (5).
3.2. Compiling and Running Code
To build a Go program, use the "go" tool. To build "helloworld" we
just enter:
% go build helloworld.go
This results in an executable called "helloworld".
% ./helloworld
Hello, world.
You can combine the above and just call "go run helloworld.go".
3.3. Variables, Types and Keywords
In the next few sections we will look at the variables, basic types,
keywords, and control structures of our new language.
Go is different from (most) other languages in that the type of a
variable is specified _after_ the variable name. So not: "int a",
Gieben Expires July 11, 2015 [Page 9]
Internet-Draft Learning Go January 2015
but "a int". When you declare a variable it is assigned the
"natural" null value for the type. This means that after "var a
int", "a" has a value of 0. With "var s string", "s" is assigned the
zero string, which is """". Declaring and assigning in Go is a two
step process, but they may be combined. Compare the following pieces
of code which have the same effect.
var a int a := 15
var b bool b := false
a = 15
b = false
On the left we use the "var" keyword to declare a variable and _then_
assign a value to it. The code on the right uses ":=" to do this in
one step (this form may only be used _inside_ functions). In that
case the variable type is _deduced_ from the value. A value of 15
indicates an "int". A value of "false" tells Go that the type should
be "bool". Multiple "var" declarations may also be grouped; "const"
(see Section 3.3.3) and "import" also allow this. Note the use of
parentheses instead of braces:
var (
x int
b bool
)
Multiple variables of the same type can also be declared on a single
line: "var x, y int" makes "x" and "y" both "int" variables. You can
also make use of _parallel assignment_: "a, b := 20, 16". This makes
"a" and "b" both integer variables and assigns 20 to "a" and 16 to
"b".
A special name for a variable is "_". Any value assigned to it is
discarded (it's similar to "/dev/null" on Unix). In this example we
only assign the integer value of 35 to "b" and discard the value 34:
"_, b := 34, 35". Declared but otherwise _unused_ variables are a
compiler error in Go.
3.3.1. Boolean Types
A boolean type represents the set of boolean truth values denoted by
the predeclared constants _true_ and _false_. The boolean type is
"bool".
Gieben Expires July 11, 2015 [Page 10]
Internet-Draft Learning Go January 2015
3.3.2. Numerical Types
Go has most of the well-known types such as "int". The "int" type
has the appropriate length for your machine, meaning that on a 32-bit
machine it is 32 bits and on a 64-bit machine it is 64 bits. Note:
an "int" is either 32 or 64 bits, no other values are defined. Same
goes for "uint", the unsigned int.
If you want to be explicit about the length, you can have that too,
with "int32", or "uint32". The full list for (signed and unsigned)
integers is "int8", "int16", "int32", "int64" and "byte", "uint8",
"uint16", "uint32", "uint64", with "byte" being an alias for "uint8".
For floating point values there is "float32" and "float64" (there is
no "float" type). A 64 bit integer or floating point value is
_always_ 64 bit, also on 32 bit architectures.
Note that these types are all distinct and assigning variables which
mix these types is a compiler error, like in the following code:
package main
func main() {
var a int
var b int32
b = a + a
b = b + 5
}
We declare two different integers, a and b where a is an "int" and b
is an "int32". We want to set b to the sum of a and a. This fails
and gives the error: "cannot use a + a (type int) as type int32 in
assignment". Adding the constant 5 to b _does_ succeed, because
constants are not typed.
3.3.3. Constants
Constants in Go are just that --- constant. They are created at
compile time, and can only be numbers, strings, or booleans; "const x
= 42" makes "x" a constant. You can use _iota_ to enumerate values.
const (
a = iota
b
)
The first use of "iota" will yield 0, so "a" is equal to 0. Whenever
"iota" is used again on a new line its value is incremented with 1,
so "b" has a value of
Gieben Expires July 11, 2015 [Page 11]
Internet-Draft Learning Go January 2015
1. Or, as shown here, you can even let Go repeat the use of "iota".
You may also explicitly type a constant: "const b string = "0"".
Now "b" is a "string" type constant.
3.3.4. Strings
Another important built-in type is "string". Assigning a string is
as simple as:
s := "Hello World!"
Strings in Go are a sequence of UTF-8 characters enclosed in double
quotes ("). If you use the single quote (') you mean one character
(encoded in UTF-8) --- which is _not_ a "string" in Go.
Once assigned to a variable, the string cannot be changed: strings in
Go are immutable. If you are coming from C, not that the following
is not legal in Go:
var s string = "hello"
s[0] = 'c'
To do this in Go you will need the following:
s := "hello"
c := []rune(s) <1>
c[0] = 'c' <2>
s2 := string(c) <3>
fmt.Printf("%s\n", s2) <4>
Here we convert "s" to an array of runes (1). We change the first
element of this array (1). Then we create a _new_ string "s2" with
the alteration (3). Finally, we print the string with "fmt.Printf"
(4).
3.3.5. Runes
"Rune" is an alias for "int32". It is an UTF-8 encoded code point.
When is this type useful? ((runes)) One example is when you're
iterating over characters in a string. You could loop over each byte
(which is only equivalent to a character when strings are encoded in
8-bit ASCII, which they are _not_ in Go!). But to get the actual
characters you should use the "rune" type.
Gieben Expires July 11, 2015 [Page 12]
Internet-Draft Learning Go January 2015
3.3.6. Complex Numbers
Go has native support for complex numbers. To use them you need a
variable of type "complex128" (64 bit real and imaginary parts) or
"complex64" (32 bit real and imaginary parts). Complex numbers are
written as "re + im"i, where "re" is the real part, "im" is the
imaginary part and i is the literal 'i' (\sqrt{-1}).
3.3.7. Errors
Any non-trivial program will have the need for error reporting sooner
or later. Because of this Go has a builtin type specially for
errors, called "error". "var e error" creates a variable "e" of type
"error" with the value "nil". This error type is an interface --
we'll look more at interfaces in chap:interfaces). For now you can
just assume that "error" is a type just like all other types.
3.4. Operators and Built-in Functions
Go supports the normal set of numerical operators. See Table 1 for
lists the current ones and their relative precedence. They all
associate from left to right.
+------------+--------------------------+
| Precedence | Operator(s) |
+------------+--------------------------+
| Highest | "* / % << >> & &^" |
| | `+ - |
| | "== != < <= > >=" |
| | "<-" |
| | "&&" |
| Lowest | || |
+------------+--------------------------+
Table 1: Operator precedence.
"+ - * /" and "%" all do what you would expect, "& | ^" and "&^" are
bit operators for bitwise _and_, bitwise _or_, bitwise _xor_, and bit
clear respectively. The "&&" and "||" operators are logical _and_
and logical _or_ . Not listed in the table is the logical not : "!"
Although Go does not support operator overloading (or method
overloading for that matter), some of the built-in operators _are_
overloaded. For instance, "+" can be used for integers, floats,
complex numbers and strings (adding strings is concatenating them).
Gieben Expires July 11, 2015 [Page 13]
Internet-Draft Learning Go January 2015
3.5. Go Keywords
Let's start looking at keywords, Table 2 lists all the keywords in
Go.
+------------+---------------+----------+-------------+----------+
| "break" | "default" | "func" | "interface" | "select" |
| "case" | "defer" | "go" | "map" | "struct" |
| "chan" | "else" | "goto" | "package" | "switch" |
| "const" | "fallthrough" | "if" | "range" | "type" |
| "continue" | "for" | "import" | "return" | "var" |
+------------+---------------+----------+-------------+----------+
Table 2: Keywords in Go.
We've seen some of these already. We used "var" and "const" in the
Section 3.3 section, and we briefly looked at "package" and "import"
in our "Hello World" program at the start of the chapter. Others
need more attention and have their own chapter or section:
o "func" is used to declare functions and methods.
o "return" is used to return from functions. We'll look at both
"func" and "return" in detail in Section 4.
o "go" is used for concurrency. We'll look at this in
Section 8.3.1.
o "select" used to choose from different types of communication,
We'll work with "select" in Section 8.3.1.
o "interface" is covered in Section 7.
o "struct" is used for abstract data types. We'll work with
"struct" in Section 6.
o "type" is also covered in Section 6.
3.6. Control Structures
There are only a few control structures in Go. To write loops we use
the "for" keyword, and there is a "switch" and of course an "if".
When working with channels "select" will be used (see Section 8.3.1).
Parentheses are are not required around the condition, and the body
must _always_ be brace-delimited.
Gieben Expires July 11, 2015 [Page 14]
Internet-Draft Learning Go January 2015
3.6.1. If-Else
In Go an "if" looks like this:
if x > 0 {
return y
} else {
return x
}
Since "if" and "switch" accept an initialization statement, it's
common to see one used to set up a (local) variable.
if err := SomeFunction(); err == nil {
// do something
} else {
return err
}
It is idomatic in Go to omit the "else" when the "if" statement's
body has a "break", "continue", "return" or, "goto", so the above
code would be better written as:
if err := SomeFunction(); err != nil {
return err
}
// do something
The opening brace on the first line must be positioned on the same
line as the "if" statement. There is no arguing about this, because
this is what "gofmt" outputs.
3.6.2. Goto
Go has a "goto" statement - use it wisely. With "goto" you jump to a
label which must be defined within the current function. For
instance, a loop in disguise:
func myfunc() {
i := 0
Here:
fmt.Println(i)
i++
goto Here
}
The string "Here:" indicates a label. A label does not need to start
with a capital letter and is case sensitive.
Gieben Expires July 11, 2015 [Page 15]
Internet-Draft Learning Go January 2015
3.6.3. For
The Go "for" loop has three forms, only one of which has semicolons:
o "for init; condition; post { }" - a loop using the syntax borrowed
from C;
o "for condition { }" - a while loop, and;
o "for { }" - an endless loop.
Short declarations make it easy to declare the index variable right
in the loop.
sum := 0
for i := 0; i < 10; i++ {
sum = sum + i
}
Note that the variable "i" ceases to exist after the loop.
3.6.4. Break and Continue
With "break" you can quit loops early. By itself, "break" breaks the
current loop.
for i := 0; i < 10; i++ {
if i > 5 {
break <1>
}
fmt.Println(i) <2>
}
Here we "break" the current loop (1), and don't continue with the
"fmt.Println(i)" statement (2). So we only print 0 to 5. With loops
within loop you can specify a label after "break" to identify _which_
loop to stop:
J: for j := 0; j < 5; j++ { <1>
for i := 0; i < 10; i++ {
if i > 5 {
break J <2>
}
fmt.Println(i)
}
}
Gieben Expires July 11, 2015 [Page 16]
Internet-Draft Learning Go January 2015
Here we define a label "J" (1), preceding the "for"-loop there. When
we use "break J" (2), we don't break the inner loop but the "J" loop.
With "continue" you begin the next iteration of the loop, skipping
any remaining code. In the same way as "break", "continue" also
accepts a label.
3.6.5. Range
The keyword "range" can be used for loops. It can loop over slices,
arrays, strings, maps and channels (see Section 8.3.1). "range" is an
iterator that, when called, returns the next key-value pair from the
"thing" it loops over. Depending on what that is, "range" returns
different things.
When looping over a slice or array, "range" returns the index in the
slice as the key and value belonging to that index. Consider this
code:
list := []string{"a", "b", "c", "d", "e", "f"}
for k, v := range list {
// do something with k and v
}
First we create a slice of strings. Then we use "range" to loop over
them. With each iteration, "range" will return the index as an "int"
and the key as a "string". It will start with 0 and "a", so "k" will
be 0 through 5, and v will be "a" through "f".
You can also use "range" on strings directly. Then it will break out
the individual Unicode characters Mostly, when people talk about
characters, they mean 8 bit characters. As UTF-8 characters may be
up to 32 bits the word rune is used. In this case the type of "char"
is "rune". and their start position, by parsing the UTF-8. The loop:
for pos, char := range "G&#337;!" {
fmt.Printf("character '%c' starts at byte position %d\n", char, pos)
}
prints
character 'G' starts at byte position 0
character '&#337;' starts at byte position 1
character '!' starts at byte position 3
Note that "&#337;" took 2 bytes, so 'x' starts at byte 3.
TODO(miek): check and change.
Gieben Expires July 11, 2015 [Page 17]
Internet-Draft Learning Go January 2015
3.6.6. Switch
Go's "switch" is very flexible; you can match on much more than just
integers. The cases are evaluated top to bottom until a match is
found, and if the "switch" has no expression it switches on "true".
It's therefore possible -- and idiomatic -- to write an "if-else-if-
else" chain as a "switch".
Convert hexadecimal character to an int value
switch { <1>
case '0' <= c && c <= '9': <2>
return c - '0' <3>
case 'a' <= c && c <= 'f': <4>
return c - 'a' + 10
case 'A' <= c && c <= 'F': <5>
return c - 'A' + 10
}
return 0
A "switch" without a condition is the same as "switch true" (1). We
list the different cases. Each "case" statement has a condition that
is either true of false. Here (2) we check if "c" is a number. If
"c" is a number we return its value (3). Check if "c" falls between
"a" and "f" (4). For an "a" we return 10, for "b" we return 11, etc.
We also do the same (5) thing for "A" to "F".
There is no automatic fall through, you can use "fallthrough" for
that.
switch i {
case 0: fallthrough
case 1: <1>
f()
default:
g() <2>
"f()" can be called when "i == 0" (1). With "default" you can
specify an action when none of the other cases match. Here "g()" is
called when "i" is not 0 or 1 (2). We could rewrite the above
example as:
switch i {
case 0, 1: <1>
f()
default:
g()
You can list cases on one line (1), separated by commas.
Gieben Expires July 11, 2015 [Page 18]
Internet-Draft Learning Go January 2015
3.7. Built-in Functions
A few functions are predefined, meaning you _don't_ have to include
any package to get access to them. Table 3 lists them all.
+----------+----------+-----------+-----------+
| "close" | "new" | "panic" | "complex" |
| "delete" | "make" | "recover" | "real" |
| "len" | "append" | "print" | "imag" |
| "cap" | "copy" | "println" | |
+----------+----------+-----------+-----------+
Table 3: Pre-defined functions in Go.
These built-in functions are documented in the "builtin" pseudo
package that is included in recent Go releases. Let's go over these
functions briefly.
close is used in channel communication. It closes a channel. We'll
learn more about this in Section 8.3.1.
delete is used for deleting entries in maps.
len and cap are used on a number of different types, "len" is used
to return the lengths of strings, slices, and arrays. In the next
section Section 3.8.1 we'll look at slices, arrays and the
function "cap".
new is used for allocating memory for user defined data types. See
#(allocation with new).
make is used for allocating memory for built-in types (maps, slices,
and channels). See #(allocation with make).
copy, append "copy" is for copying slices. And "append" is for
concatenating slices. See Section 3.8.2 in this chapter.
panic, recover are used for an _exception_ mechanism. See
Section 4.6 for more.
print, println are low level printing functions that can be used
without reverting to the "fmt" package. These are mainly used for
debugging.
complex, real, imag all deal with complex numbers. We will not use
complex numbers in this book.
Gieben Expires July 11, 2015 [Page 19]
Internet-Draft Learning Go January 2015
3.8. Arrays, Slices, and Maps
To store multiple values in a list, you can use arrays, or their more
flexible cousin: slices. A dictionary or hash type is also
available. It is called a "map" in Go.
3.8.1. Arrays
An array is defined by: "[n]<type>", where n is the length of the
array and "<type>" is the stuff you want to store. To assign or
index an element in the array, you use square brackets:
var arr [10]int
arr[0] = 42
arr[1] = 13
fmt.Printf("The first element is %d\n", arr[0])
Array types like "var arr [10]int" have a fixed size. The size is
_part_ of the type. They can't grow, because then they would have a
different type. Also arrays are values: Assigning one array to
another _copies_ all the elements. In particular, if you pass an
array to a function it will receive a copy of the array, not a
pointer to it.
To declare an array you can use the following: "var a [3]int". To
initialize it to something other than zero, use a _composite literal_
: "a := [3]int{1, 2, 3}". This can be shortened to "a := [...]int{1,
2, 3}", where Go counts the elements automatically.
A composite literal allows you to assign a value directly to an
array, slice, or map. See Section 6.1.3 for more information.
When declaring arrays you _always_ have to type something in between
the square brackets, either a number or three dots ("..."), when
using a composite literal. When using multidimensional arrays, you
can use the following syntax: "a := [2][2]int{ {1,2}, {3,4} }". Now
that you know about arrays you will be delighted to learn that you
will almost never use them in Go, because there is something much
more flexible: slices.
3.8.2. Slices
A slice is similar to an array, but it can grow when new elements are
added. A slice always refers to an underlying array. What makes
slices different from arrays is that a slice is a pointer _to_ an
array; slices are reference types.
Gieben Expires July 11, 2015 [Page 20]
Internet-Draft Learning Go January 2015
Reference types are created with "make". We detail this further
in Section 6.
That means that if you assign one slice to another, both refer to the
_same_ underlying array. For instance, if a function takes a slice
argument, changes it makes to the elements of the slice will be
visible to the caller, analogous to passing a pointer to the
underlying array. With: "slice := make([]int, 10)", you create a
slice which can hold ten elements. Note that the underlying array
isn't specified. A slice is always coupled to an array that has a
fixed size. For slices we define a capacity and a length . Figure 1
shows the creation of an array, then the creation of a slice. First
we create an array of m elements of the type "int": "var array[m]int"
.
Next, we create a slice from this array: "slice := array[:n]" . And
now we have:
o "len(slice) == n"
o "cap(slice) == m"
o "len(array) == cap(array) == m"
fig/array-vs-slice.png
Array versus slice [4]
Figure 1: An array versus a slice.
Given an array, or another slice, a new slice is created via
"a[n:m]". This creates a new slice which refers to the variable "a",
starts at index "n", and ends before index "m". It has length "n -
m".
a := [...]int{1, 2, 3, 4, 5} <1>
s1 := a[2:4] <2>
s2 := a[1:5] <3>
s3 := a[:] <4>
s4 := a[:4] <5>
s6 := a[2:4:5] <6>
First we define (1) an array with five elements, from index 0 to 4.
From this we create (2) a slice with the elements from index 2 to 3,
this slices contains: "3, 4". Then we we create another slice (3)
from "a": with the elements from index 1 to 4, this contains: "2, 3,
4, 5". With "a:[:]" (4) we create a slice with of all the elements
in the array. This is a shorthand for: "a[0:len(a)]". And with
Gieben Expires July 11, 2015 [Page 21]
Internet-Draft Learning Go January 2015
"a[:4]" (5) we create a slice with the elements from index 0 to 3,
this is short for: "a[0:4]", and gives us a slices that contains: "1,
2, 3, 4". With "s2[:]" we create a slice from the slice "s2" (6),
note that "s5" still refers to the array "a". Finally, we create a
slice with the elements from index 3 to 3 _and_ also set the cap to 4
(6).
When working with slices you can overrun the bounds, consider this
code.
package main
func main() {
var array [100]int <1>
slice := array[0:99] <2>
slice[98] = 1 <3>
slice[99] = 2 <4>
}
At (1) we create an array with a 100 elements, indexed from 0 to 99.
Then at (2) we create a slice that has index 0 to 98. We assign 1 to
the 99th element (3) of the slice. This works as expected. But at
(4) we dare to do the impossible, and and try to allocate something
beyond the length of the slice and we are greeted with a _runtime_
error: "Error: "throw: index out of range"."
If you want to extend a slice, there are a couple of built-in
functions that make life easier: "append" and "copy". The append
function appends zero or more values to a slice and returns the
result: a slice with the same type as the original. If the original
slice isn't big enough to fit the added values, append will allocate
a new slice that is big enough. So the slice returned by append may
refer to a different underlying array than the original slice does.
Here's an example:
s0 := []int{0, 0}
s1 := append(s0, 2) <1>
s2 := append(s1, 3, 5, 7) <2>
s3 := append(s2, s0...) <3>
At (1) we append a single element, making "s1" equal to "[]int{0, 0,
2}". At (2) we append multiple elements, making "s2" equal to
"[]int{0, 0, 2, 3, 5, 7}". And at (3) we append a slice, giving us
"s3" equal to "[]int{0, 0, 2, 3, 5, 7, 0, 0}". Note the three dots
used after "s0..."! This is needed make it clear explicit that
you're appending another slice, instead of a single value.
Gieben Expires July 11, 2015 [Page 22]
Internet-Draft Learning Go January 2015
The copy function copies slice elements from a source to a
destination, and returns the number of elements it copied. This
number is the minimum of the length of the source and the length of
the destination. For example:
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
n1 := copy(s, a[0:]) <1>
n2 := copy(s, s[2:]) <2>
After (1), "n1" is 6, and "s" is "[]int{0, 1, 2, 3, 4, 5}". And
after (2), "n2" is 4, and "s" is "[]int{2, 3, 4, 5, 4, 5}".
3.8.3. Maps
Many other languages have a type similar to maps built-in. For
instance, Perl has hashes, Python has its dictionaries, and C++ also
has maps (as part of the libraries). In Go we have the "map" type.
A "map" can be thought of as an array indexed by strings (in its most
simple form).
monthdays := map[string]int{
"Jan": 31, "Feb": 28, "Mar": 31,
"Apr": 30, "May": 31, "Jun": 30,
"Jul": 31, "Aug": 31, "Sep": 30,
"Oct": 31, "Nov": 30, "Dec": 31, <1>
}
The general syntax for defining a map is "map[<from type>]<to type>".
Here, we define a map that converts from a "string" (month
abbreviation) to an "int" (number of days in that month). Note that
the trailing comma at (1) is _required_.
Use "make" when only declaring a map: "monthdays :=
make(map[string]int)". A map is a reference type.
For indexing ("searching") the map, we use square brackets. For
example, suppose we want to print the number of days in December:
"fmt.Printf("%d\n", monthdays["Dec"])"
If you are looping over an array, slice, string, or map a, "range"
clause will help you again, it returns the key and corresponding
value with each invocation.
Gieben Expires July 11, 2015 [Page 23]
Internet-Draft Learning Go January 2015
year := 0
for _, days := range monthdays <1>
year += days
}
fmt.Printf("Numbers of days in a year: %d\n", year)
At (1) we use the underscore to ignore (assign to nothing) the key
returned by "range". We are only interested in the values from
"monthdays".
To add elements to the map, you would add new month with:
"monthdays["Undecim"] = 30". If you use a key that already exists,
the value will be silently overwritten: "monthdays["Feb"] = 29". To
test for existence , you would use the following: "value, present :=
monthdays["Jan"]". If the key "Jan" exists, "present" will be true.
It's more Go like to name "present" "ok", and use: "v, ok :=
monthdays["Jan"]". In Go we call this the "comma ok" form.
You can remove elements from the "map": "delete(monthdays, "Mar")" .
In general the syntax "delete(m, x)" will delete the map entry
retrieved by the expression "m[x]".
3.9. Exercises
3.9.1. For-loop
1. Create a loop with the "for" construct. Make it loop 10 times
and print out the loop counter with the "fmt" package.
2. Rewrite the loop from to use "goto". The keyword "for" may not
be used.
3. Rewrite the loop again so that it fills an array and then prints
that array to the screen.
3.9.2. Answer
1. There are many possibilities. One solutions could be:
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
fmt.Println("%d", i)
}
}
Gieben Expires July 11, 2015 [Page 24]
Internet-Draft Learning Go January 2015
Let's compile this and look at the output.
% go build for.go
% ./for
0
1
.
.
.
9
2. Rewriting the loop results in code that should look something
like this (only showing the "main"-function):
func main() {
i := 0 <1>
Loop: <2>
if i < 10 {
fmt.Printf("%d\n", i)
i++
goto Loop <3>
}
}
At (1) we define our loop variable. And at (2) we define a label and
at (3) we jump to this label.
1. The following is one possible solution:
package main
import "fmt"
func main() {
var arr [10]int <1>
for i := 0; i < 10; i++ {
arr[i] = i <2>
}
fmt.Printf("%v", arr) <3>
}
Here (1) we create an array with 10 elements. Which we then fill
(2) one by one. And finally we print it (3) with "%v" which lets
Go to print the value for us. You could even do this in one fell
swoop by using a composite literal:
fmt.Printf("%v\n", [...]int{0,1,2,3,4,5,6,7,8,9})
Gieben Expires July 11, 2015 [Page 25]
Internet-Draft Learning Go January 2015
3.9.3. Average
1. Write code to calculate the average of a "float64" slice. In a
later exercise you will make it into a function.
3.9.4. Answer
1. The following code calculates the average.
sum := 0.0
switch len(xs) {
case 0: <1>
avg = 0
default: <2>
for _, v := range xs {
sum += v
}
avg = sum / float64(len(xs)) <3>
}
Here at (1) we check if the length is zero and if so, we return 0.
Otherwise we calculate the average at (2). We have to convert the
value return from "len" to a "float64" to make the division work at
(3).
3.9.5. FizzBuzz
1. Solve this problem, called the Fizz-Buzz [fizzbuzz_cite] problem:
Write a program that prints the numbers from 1 to 100. But for
multiples of three print, "Fizz" instead of the number, and for
multiples of five, print "Buzz". For numbers which are multiples of
both three and five, print "FizzBuzz".
3.9.6. Answer
1. A possible solution to this problem is the following program.
Gieben Expires July 11, 2015 [Page 26]
Internet-Draft Learning Go January 2015
package main
import "fmt"
func main() {
const (
FIZZ = 3 <1>
BUZZ = 5
)
var p bool <2>
for i := 1; i < 100; i++ { <3>
p = false
if i%FIZZ == 0 { <4>
fmt.Printf("Fizz")
p = true
}
if i%BUZZ == 0 { <5>
fmt.Printf("Buzz")
p = true
}
if !p { <6>
fmt.Printf("%v", i)
}
fmt.Println()
}
}
Here (1) we define two constants to make our code more readable, see
Section 3.3.3. At (2) we define a boolean that keeps track if we
already printed something. At (3) we start our for-loop, see
Section 3.6.3. If the value is divisible by FIZZ - that is, 3 - , we
print "Fizz" (4). And at (5) we check if the value is divisble by
BUZZ -- that is, 5 -- if so print "Buzz". Note that we have also
taken care of the FizzBuzz case. At (6), if printed neither Fizz nor
Buzz printed, we print the value.
4. Functions
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?
-- , Richard P. Gabriel
Gieben Expires July 11, 2015 [Page 27]
Internet-Draft Learning Go January 2015
Functions are the basic building blocks of Go programs; all
interesting stuff happens in them.
Here is an example of how you can declare a function:
type mytype int
func (p mytype) funcname(q int) (r,s int) { return 0,0 }
<1> <2> <3> <4> <5> <6>
To declare a function, you use the "func" keyword (1). You can
optionally bind (2) to a specific type called receiver (a function
with a receiver is usually called an method . This will be explored
in Chapter Section 7. Next (3) you write the name of your function.
Here (4) we define that the variable "q" of type "int" is the input
parameter. Parameters are passed _pass-by-value_. The variables "r"
and "s" (5) are the _named return parameters_ for this function.
Functions in Go can have multiple return values. This is very useful
to return a value _and_ and error. This removes the need for in-band
error returns (such as -1 for "EOF") and modifying an argument. If
you want the return parameters not to be named you only give the
types: "(int, int)". If you have only one value to return you may
omit the parentheses. If your function is a subroutine and does not
have anything to return you may omit this entirely. Finally, we have
the body (6) of the function. Note that "return" is a statement so
the braces around the parameter(s) are optional.
As said 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
"return" statement with no arguments, the current values of the
result parameters are returned. Using these features enables you
(again) to do more with less code.
The names are not mandatory but they can make code shorter and
clearer: _they are documentation_. However don't overuse this
features, especially in longer function where it might not be
immediately apperent what is returned.
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 does not allow nested functions, but you can
work around this with anonymous functions. See the
Section Section 4.2 in this chapter. Recursive functions work just
as in other languages:
Gieben Expires July 11, 2015 [Page 28]
Internet-Draft Learning Go January 2015
func rec(i int) {
if i == 10 { <1>
return
}
rec(i+1) <2>
fmt.Printf("%d ", i)
}
Here (2) we call the same function again, "rec" returns when "i" has
the value 10, this is checked on the second line (1). This function
prints: "9 8 7 6 5 4 3 2 1 0", when called as "rec(0)".
4.1. Scope
Variables declared outside any functions are _global_ in Go, those
defined in functions are _local_ to those functions. If names
overlap - a local variable is declared with the same name as a global
one
o the local variable hides the global one when the current function
is executed.
In the following example we call "g()" from "f()":
package main
var a int
func main() {
a = 5
print(a)
f()
}
func f() {
a := 6
print(a)
g()
}
func g() {
print(a)
}
On line 3 we declare "a" to be a global variable of type "int". Then
in the "main" function we give the _global_ "a" the value of 5, after
printing it we call the function "f". Then on line 12 "a := 6", we
create a _new, local_ variable also called "a". This new "a" gets
Gieben Expires July 11, 2015 [Page 29]
Internet-Draft Learning Go January 2015
the value of 6, which we then print. Then we call "g", which uses
the _global_ "a" again and prints "a"'s value set in "main". Thus
the output will be: "565". A _local_ variable is _only_ valid when
we are executing the function in which it is defined. Note that the
":=" used in line 12 is sometimes hard to spot so it is generally
advised _not_ to use the same name for global and local variables.
4.2. Functions as values
As with almost everything in Go, functions are also _just_ values.
They can be assigned to variables as follows:
import "fmt"
func main() {
a := func() { <1>
fmt.Println("Hello")
} <2>
a() <3>
}
Define a nameless function and assign to "a". No "()" here. If
there were we would _call_ the function in "a". _Now_ we call the
function.
Functions--as--values may be used in other places, for example maps.
Here we convert from integers to functions:
var xs = map[int]func() int{
1: func() int { return 10 },
2: func() int { return 20 },
3: func() int { return 30 },
}
Note that the final comma on second to last line is _mandatory_.
Or you can write a function that takes a function as its parameter,
for example a "Map" function that works on "int" slices. This is
left as an exercise for the reader; see the exercise (#map function).
4.3. Callbacks
Because functions are values they are easy to pass to functions, from
where they can be used as callbacks. First define a function that
does "something" with an integer value:
Gieben Expires July 11, 2015 [Page 30]
Internet-Draft Learning Go January 2015
func printit(x int)
fmt.Printf("%v\n", x)
}
This function does not return a value and just prints its argument.
The _signature_ of this function is: "func printit(int)", or without
the function name: "func(int)". To create a new function that uses
this one as a callback we need to use this signature:
func callback(y int, f func(int)) {
f(y)
}
Here we create a new function that takes two parameters: "y int",
i.e. just an "int" and "f func(int)", i.e. a function that takes an
int and returns nothing. The parameter "f" is the variable holding
that function. It can be used as any other function, and we exectute
the function on line 2 with the parameter "y": "f(y)"
4.4. 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:
func ReadWrite() bool {
file.Open("file")
Do your thing
if failureX {
file.Close() <1>
return false
}
if failureY {
file.Close() <2>
return false
}
file.Close() <3>
return true <4>
}
Note that we repeat a lot of code here; you can see the that
"file.Close()" is called at (1, 2, 3). To overcome this, Go has the
"defer" keyword. After "defer" you specify a function which is
called just _before_ (4) the current function exits.
Gieben Expires July 11, 2015 [Page 31]
Internet-Draft Learning Go January 2015
With "defer" we can rewrite the above code as follows. It makes the
function more readable and it puts the "Close" _right next_ to the
"Open".
func ReadWrite() bool {
file.Open("filename")
defer file.Close() <1>
Do your thing
if failureX {
return false <2>
}
if failureY {
return false <3>
}
return true <4>
}
At (1) "file.Close()" is added to the defer list. "Close" is now
done automatically at (2, 3, 4). This makes the function shorter and
more readable. It puts the "Close" right next to the "Open".
You can put multiple functions on the "defer list", like this example
from
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
Deferred functions are executed in LIFO order, so the above code
prints: "4 3 2 1 0".
With "defer" you can even change return values, provided that you are
using named result parameters and a function literal , i.e:
defer func() {/* ... */}()
Here we use a function without a name and specify the body of the
function inline, basically we're creating a nameless function on the
spot. The final braces are needed because "defer" needs a function
call, not a function value. If our anonymous function would take an
parameter it would be easier to see why we need the braces:
defer func(x int) {/* ... */}(5)
In this (unnamed) function you can access any named return parameter:
Gieben Expires July 11, 2015 [Page 32]
Internet-Draft Learning Go January 2015
func f() (ret int)
defer func() { <1>
ret++
}()
return 0
}
Here (1) we specify our function, the named return value "ret" is
initialized with zero. The nameless function in the defer increments
the value of "ret" with
1. The "return 0" on line 5 _will not be the returned value_,
because of "defer". The function "f" will return 1!
4.5. Variadic Parameter
Functions that take a variable number of parameters are known as
variadic functions. To declare a function as variadic, do something
like this:
func myfunc(arg ...int) {}
The "arg ...int" instructs Go to see this as a function that takes a
variable number of arguments. Note that these arguments all have to
have the type "int". In the body of your function the variable "arg"
is a slice of ints:
for _, n := range arg {
fmt.Printf("And the number is: %d\n", n)
}
We range over the arguments on the first line. We are not interested
in the index as returned by "range", hence the use of the underscore
there. In the body of the "range" we just print the parameters we
were given.
If you don't specify the type of the variadic argument it defaults to
the empty interface "interface{}" (see Chapter Section 7).
Suppose we have another variadic function called "myfunc2", the
following example shows how to pass variadic arguments to it:
func myfunc(arg ...int) {
myfunc2(arg...)
myfunc2(arg[:2]...)
}
Gieben Expires July 11, 2015 [Page 33]
Internet-Draft Learning Go January 2015
With "myfunc2(arg...)" we pass all the parameters to "myfunc2", but
because the variadic parameters is just a slice, we can use some
slice tricks as well.
4.6. Panic and recovering
Go does not have an exception mechanism: you cannot throw exceptions.
Instead it uses a panic-and-recover mechanism. It is worth
remembering that you should use this as a last resort, your code will
not look, or be, better if it is littered with panics. It's a
powerful tool: use it wisely. So, how do you use it? In the words
of the Go Authors [go_blog_panic]:
Panic is a built-in function that stops the ordinary flow of control
and begins panicking. When the function "F" calls "panic",
execution of "F" stops, any deferred functions in "F" are executed
normally, and then "F" returns to its caller. To the caller, "F"
then behaves like a call to "panic". The process continues up the
stack until all functions in the current goroutine have returned,
at which point the program crashes. Panics can be initiated by
invoking "panic" directly. They can also be caused by _runtime
errors_, such as out-of-bounds array accesses.
Recover is a built-in function that regains control of a panicking
goroutine. Recover is _only_ useful inside _deferred_ functions.
During normal execution, a call to "recover" will return "nil" and
have no other effect. If the current goroutine is panicking, a
call to "recover" will capture the value given to "panic" and
resume normal execution.
This function checks if the function it gets as argument will panic
when it is executed:
func Panic(f func()) (b bool) { <1>
defer func() { <2>
if x := recover(); x != nil {
b = true
}
}()
f() <3>
return <4>
}
We define a new function "Panic" (1) that takes a function as an
argument (see Section 4.2). It returns true if "f" panics when run,
else false. We then (2) define a "defer" function that utilizes
"recover". If the current goroutine panics, this defer function will
notice that. If "recover()" returns non-"nil" we set "b" to true.
Gieben Expires July 11, 2015 [Page 34]
Internet-Draft Learning Go January 2015
At (3) Execute the function we received as the argument. And finally
(4) we return the value of "b". Because "b" is a named return
parameter.
The following code fragment, shows how we can use this function:
func panicy() {
var a []int
a[3] = 5
}
func main() {
fmt.Println(Panic(panicy))
}
On line 3 the "a[3] = 5" triggers a _runtime_ out of bounds error
which results in a panic. Thus this program will print "true". If
we change line 2: "var a []int" to "var a [3]int" the function
"panicy" does not panic anymore. Why?
4.7. Exercises
4.7.1. Average
1. Write a function that calculates the average of a "float64"
slice.
4.7.2. Answer
1. The following function calculates the average:
package main
func average(xs []float64) (avg float64) { <1>
sum := 0.0
switch len(xs) {
case 0: <2>
avg = 0
default: <3>
for _, v := range xs {
sum += v
}
avg = sum / float64(len(xs)) <4>
}
return <5>
}
Gieben Expires July 11, 2015 [Page 35]
Internet-Draft Learning Go January 2015
At (1) we use a named return parameter. If the length of "xs" is
zero (2), we return 0. Otherwise (3), we calculate the average. At
(4) we convert the value to a "float64" to make the division work as
"len" returns an "int". Finally, at (5) we reutrn our avarage.
4.7.3. Bubble sort
1. Write a function that performs a bubble sort on a slice of ints.
From [bubblesort]:
It works by repeatedly stepping through the list to be sorted,
comparing each pair of adjacent items and swapping them if they
are in the wrong order. The pass through the list is repeated
until no swaps are needed, which indicates that the list is
sorted. The algorithm gets its name from the way smaller elements
"bubble" to the top of the list.
It also gives an example in pseudo code:
procedure bubbleSort( A : list of sortable items )
do
swapped = false
for each i in 1 to length(A) - 1 inclusive do:
if A[i-1] > A[i] then
swap( A[i-1], A[i] )
swapped = true
end if
end for
while swapped
end procedure
4.7.4. Answer
1. Bubble sort isn't terribly efficient. For n elements it scales
O(n^2). But bubble sort is easy to implement:
Gieben Expires July 11, 2015 [Page 36]
Internet-Draft Learning Go January 2015
func main() {
n := []int{5, -1, 0, 12, 3, 5}
fmt.Printf("unsorted %v\n", n)
bubblesort(n)
fmt.Printf("sorted %v\n", n)
}
func bubblesort(n []int) {
for i := 0; i < len(n)-1; i++ {
for j := i + 1; j < len(n); j++ {
if n[j] < n[i] {
n[i], n[j] = n[j], n[i]
}
}
Because a slice is a reference type, the "bubblesort" function
works and does not need to return a sorted slice.
4.7.5. For-loop II
1. Take what you did in exercise to write the for loop and extend it
a bit. Put the body of the for loop - the "fmt.Printf" - in a
separate function.
4.7.6. Answer
1.
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
show(i)
}
}
func show(j int) {
fmt.Printf("%d\n", j)
}
4.7.7. Fibonacci
1. The Fibonacci sequence starts as follows: 1, 1, 2, 3, 5, 8, 13,
\ldots Or in mathematical terms: x_1 = 1; x_2 = 1; x_n = x_{n-1}
+ x_{n-2}\quad\forall n > 2 . Write a function that takes an
"int" value and gives that many terms of the Fibonacci sequence.
Gieben Expires July 11, 2015 [Page 37]
Internet-Draft Learning Go January 2015
4.7.8. Answer
1. The following program calculates Fibonacci numbers:
package main
import "fmt"
func fibonacci(value int) []int {
x := make([]int, value) <1>
x[0], x[1] = 1, 1 <2>
for n := 2; n < value; n++ {
x[n] = x[n-1] + x[n-2] <3>
}
return x <4>
}
func main() {
for _, term := range fibonacci(10) { <5>
fmt.Printf("%v ", term)
}
}
At (1) we create an array to hold the integers up to the value given
in the function call. At (2) we start the Fibonacci calculation.
Then (3, 4): x_n = x_{n-1} + x_{n-2}. At <4> we return the _entire_
array. And at (5) we use the "range" keyword to "walk" the numbers
returned by the Fibonacci function. Here up to 10. Finally, we
print the numbers.
4.7.9. Var args
1. Write a function that takes a variable number of ints and print
each integer on a separate line.
4.7.10. Answer
1. For this we need the "{...}"-syntax to signal we define a
function that takes an arbitrary number of arguments.
Gieben Expires July 11, 2015 [Page 38]
Internet-Draft Learning Go January 2015
package main
import "fmt"
func main() {
printthem(1, 4, 5, 7, 4)
printthem(1, 2, 4)
}
func printthem(numbers ...int) {
for _, d := range numbers {
fmt.Printf("%d\n", d)
}
}
4.7.11. Functions that return functions
1. Write a function that returns a function that performs a +2 on
integers. Name the function "plusTwo". You should then be able
do the following:
p := plusTwo()
fmt.Printf("%v\n", p(2))
Which should print 4. See Section 4.3.
2. Generalize the function from above and and create a "plusX(x)"
which returns functions that add "x" to an integer.
4.7.12. Answer
1.
func main() {
p2 := plusTwo()
fmt.Printf("%v\n",p2(2))
}
func plusTwo() func(int) int { <1>
return func(x int) int { return x + 2 } <2>
}
Define a new function that returns a function: "return func(x int)
int { return x + 2 }" Function literals at work, we define the +2--
function right there in the return statement.
1. Here we use a closure:
Gieben Expires July 11, 2015 [Page 39]
Internet-Draft Learning Go January 2015
func plusX(x int) func(int) int { <1>
return func(y int) int { return x + y } <2>
}
Here (1), we again define a function that returns a function. We use
the _local_ variable "x" in the function literal at (2).
4.7.13. Minimum
1. Write a function that finds the maximum value in an "int" slice
("[]int").
4.7.14. Answer
1. This function returns the largest int in the slice \var{l}:
func max(l []int) (max int) { <1>
max = l[0]
for _, v := range l { <2>
if v > max { <3>
max = v
}
}
return <4>
}
At (1) we use a named return parameter. At (2) we loop over "l".
The index of the element is not important. At (3), if we find a new
maximum, we remember it. And at (4) we have a "lone" return; the
current value of "max" is now returned.
4.7.15. Map function
A "map()"-function is a function that takes a function and a list.
The function is applied to each member in the list and a new list
containing these calculated values is returned. Thus:
\mathrm{map}(f(), (a_1,a_2,\ldots,a_{n-1},a_n)) = (f(a_1),
f(a_2),\ldots,f(a_{n-1}), f(a_n))
1. Write a simple "map()"-function in Go. It is sufficient for this
function only to work for ints.
4.7.16. Answer
1. A possible answer:
func Map(f func(int) int, l []int) []int {
Gieben Expires July 11, 2015 [Page 40]
Internet-Draft Learning Go January 2015
j := make([]int, len(l))
for k, v := range l {
j[k] = f(v)
}
return j
}
func main() {
m := []int{1, 3, 4}
f := func(i int) int {
return i * i
}
fmt.Printf("%v", (Map(f, m)))
}
4.7.17. Stack
1. Create a simple stack which can hold a fixed number of ints. It
does not have to grow beyond this limit. Define "push" -- put
something on the stack -- and "pop" -- retrieve something from
the stack -- functions. The stack should be a LIFO (last in,
first out) stack.
fig/stack.png
A stack [5]
A stack.
1. Write a "String" method which converts the stack to a string
representation. The stack in the figure could be represented as:
"[0:m] [1:l] [2:k]" .
4.7.18. Answer
1. First we define a new type that represents a stack; we need an
array (to hold the keys) and an index, which points to the last
element. Our small stack can only hold 10 elements.
type stack struct {
i int
data [10]int
}
Next we need the \func{push} and \func{pop} functions to actually use
the thing. First we show the _wrong_ solution!
Gieben Expires July 11, 2015 [Page 41]
Internet-Draft Learning Go January 2015
In Go, data passed to functions is _passed-by-value_ meaning a copy
is created and given to the function. The first stab for the
function "push" could be:
func (s stack) push(k int) {
if s.i+1 > 9 {
return
}
s.data[s.i] = k
s.i++
}
The function works on the "s" which is of the type "stack". To use
this we just call "s.push(50)", to push the integer 50 on the stack.
But the push function gets a copy of "s", so it is _not_ working on
the _real_ thing. Nothing gets pushed to our stack. For example the
following code:
var s stack
s.push(25)
fmt.Printf("stack %v\n", s);
s.push(14)
fmt.Printf("stack %v\n", s);
prints:
stack [0:0]
stack [0:0]
To solve this we need to give the function "push" a pointer to the
stack. This means we need to change "push" from
func (s stack) push(k int)
to
func (s *stack) push(k int).
We should now use "new()" (see Section 6.1.1). in Section 6 to
create a _pointer_ to a newly allocated "stack", so line 1 from the
example above needs to be "s := new(stack)" .
And our two functions become:
Gieben Expires July 11, 2015 [Page 42]
Internet-Draft Learning Go January 2015
func (s *stack) push(k int) {
s.data[s.i] = k
s.i++
}
func (s *stack) pop() int {
s.i--
ret := s.data[s.i]
s.data[s.i] = 0
return ret
}
Which we then use as follows:
func main() {
var s stack
s.push(25)
s.push(14)
fmt.Printf("stack %v\n", s)
}
1. "fmt.Printf("%v")" can print any value ("%v") that satisfies the
"Stringer" interface (see Section 7). For this to work we only
need to define a "String()" function for our type:
func (s stack) String() string {
var str string
for i := 0; i <= s.i; i++ {
str = str + "[" +
strconv.Itoa(i) + ":" + strconv.Itoa(s.data[i]) + "]"
}
return str
}
5. Packages
"^"
-- Answer to whether there is a bit wise negation operator., Ken
Thompson
A package is a collection of functions and data.
You declare a package with the "package" keyword. The filename does
not have to match the package name. The convention for package names
is to use lowercase characters. Go packages may consist of multiple
Gieben Expires July 11, 2015 [Page 43]
Internet-Draft Learning Go January 2015
files, but they share the "package <name>" line. Let's define a
package "even" in the file "even.go".
package even <1>
func Even(i int) bool { <2>
return i % 2 == 0
}
func odd(i int) bool { <3>
return i % 2 == 1
}
Here (1) we start a new namespace: "even". The function "Even" (2)
starts with a capital letter. This means the function is _exported_,
and may be used outside our package (more on that later). The
function "odd" (3) does not start with a capital letter, so it is a
_private_ function.
Now we just need to build the package. We create a directory under
"$GOPATH", and copy "even.go" there (see Section 3.2 in Section 3).
% mkdir $GOPATH/src/even
% cp even.go $GOPATH/src/even
% go build
% go install
Now we can use the package in our own program "myeven.go":
package main
import ( <1>
"even" <2>
"fmt" <3>
)
func main() {
i := 5
fmt.Printf("Is %d even? %v\n", i, even.Even(i)) <4>
}
Import (1) the following packages. The _local_ package "even" is
imported here (2). This (3) imports the official "fmt" package. And
now we use (4) the function from the "even" package. The syntax for
accessing a function from a package is "<package>.FunctionName()".
And finally we can build our program.
Gieben Expires July 11, 2015 [Page 44]
Internet-Draft Learning Go January 2015
% go build myeven.go
% ./myeven
Is 5 even? false
If we change our "myeven.go" at <4> to use the unexported function
"even.odd": "fmt.Printf("Is %d even? %v\n", i, even.odd(i))" We get
an error when compiling, because we are trying to use a _private_
function:
myeven.go: cannot refer to unexported name even.odd
Note that the "starts with captial \rightarrow exported", "starts
with lower-case \rightarrow private" rule also extends to other names
(new types, global variables) defined in the package. Note that the
term "capital" is not limited to US-ASCII -- it extends to all
bicameral alphabets (Latin, Greek, Cyrillic, Armenian and Coptic).
5.1. Identifiers
The Go standard library names some function with the old (Unix) names
while others are in CamelCase. The convention is to leave well-known
legacy not-quite-words alone rather than try to figure out where the
capital letters go: "Atoi", "Getwd", "Chmod". CamelCasing works best
when you have whole words to work with: "ReadFile", "NewWriter",
"MakeSlice". The convention in Go is to use CamelCase rather than
underscores to write multi-word names.
As we did above in our "myeven" program, accessing content from an
imported (with "import" ) package is done with using the package's
name and then a dot. After "import "bytes"" the importing program
can talk about "bytes.Buffer". A package name should be good, short,
concise and evocative. The convention in Go is that package names
are lowercase, single word names.
The package name used in the "import" statement is the default name
used. But if the need arises (two different packages with the same
name for instance), you can override this default: "import bar
"bytes"" The function "Buffer" is now accessed as "bar.Buffer".
Another convention is that the package name is the base name of its
source directory; the package in "src/compress/gzip" is imported as
"compress/gzip" but has name "gzip", not "compress/gzip".
It is important to avoid stuttering when naming naming things. For
instance, the buffered reader type in the "bufio" package is called
"Reader", not "BufReader", because users see it as "bufio.Reader",
which is a clear, concise name.
Gieben Expires July 11, 2015 [Page 45]
Internet-Draft Learning Go January 2015
Similarly, the function to make new instances of "ring.Ring" (package
"container/ring"), would normally be called "NewRing", but since
"Ring" is the only type exported by the package, and since the
package is called "ring", it's called just "New". Clients of the
package see that as "ring.New". Use the package structure to help
you choose good names.
Another short example is "once.Do" (see package "sync");
"once.Do(setup)" reads well and would not be improved by writing
"once.DoOrWaitUntilDone(setup)". Long names don't automatically make
things more readable.
5.2. Documenting packages
When we created our "even" package, we skipped over an important
item: documentation. Each package should have a _package comment_, a
block comment preceding the "package" clause. In our case we should
extend the beginning of the package \gocircle{1}, with:
// The even package implements a fast function for detecting if an integer
// is even or not.
package even
When running "go doc" this will show up at the top of the page. When
a package consists out of multiple files the package comment should
only appear in one file. A common convention (in really big
packages) is to have a separate "doc.go" that only holds the package
comment. Here is a snippet from the official "regexp" package:
/*
The regexp package implements a simple library for
regular expressions.
The syntax of the regular expressions accepted is:
regexp:
concatenation { '|' concatenation }
*/
package regexp
Each defined (and exported) function should have a small line of text
documenting the behavior of the function. Again to extend our "even"
package:
// Even returns true of i is even. Otherwise false is returned.
func Even(i int) bool {
Gieben Expires July 11, 2015 [Page 46]
Internet-Draft Learning Go January 2015
And even though "odd" is not exported, it's good form to document it
as well.
// odd is to opposite of Even.
func odd(i int) bool {
5.3. Testing packages
In Go it is customary to write (unit) tests for your package.
Writing tests involves the "testing" package and the program "go
test". Both have excellent documentation.
The "go test" program runs all the test functions. Without any
defined tests for our "even" package, "go test" yields:
% go test
? even [no test files]
Let us fix this by defining a test in a test file. Test files reside
in the package directory and are named "*_test.go". Those test files
are just like other Go programs, but "go test" will only execute the
test functions. Each test function has the same signature and its
name should start with "Test": "func TestXxx(t *testing.T)" .
When writing test you will need to tell "go test" whether a test was
successful or not. A successful test function just returns. When
the test fails you can signal this with the following functions.
These are the most important ones (see "go doc testing" or "go help
testfunc" for more):
o "func (t *T) Fail()", "Fail" marks the test function as having
failed but continues execution.
o "func (t *T) FailNow()", "FailNow" marks the test function as
having failed and stops its execution. Any remaining tests in
this file are skipped, and execution continues with the next test.
o "func (t *T) Log(args ...interface{})", "Log" formats its
arguments using default formatting, analogous to "Print()", and
records the text in the error log.
o "func (t *T) Fatal(args ...interface{})", "Fatal" is equivalent to
"Log()" followed by "FailNow()".
Putting all this together we can write our test. First we pick a
name: "even_test.go". Then we add the following contents:
Gieben Expires July 11, 2015 [Page 47]
Internet-Draft Learning Go January 2015
package even <1>
import "testing" <2>
func TestEven(t *testing.T) { <3>
if !Even(2) {
t.Log("2 should be even!")
t.Fail()
}
}
A test file belongs to the current (1) package. This is not only
convenient, but also allows tests of unexported functions and
structures. We then (2) import the "testing" package. And finally
the test we want to execute. The code here (3) should hold no
surprises: we check if the "Even" function works OK. And now, the
moment we have been waiting form executing the test.
% go test
ok even 0.001s
Our test ran and reported "ok". Success! If we redefine our test
function, we can see the result of a failed test:
// Entering the twilight zone
func TestEven(t *testing.T) {
if Even(2) {
t.Log("2 should be odd!")
t.Fail()
}
}
We now get:
FAIL even 0.004s
--- FAIL: TestEven (0.00 seconds)
2 should be odd!
FAIL
And you can act accordingly (by fixing the test for instance).
Writing new packages should go hand in hand with writing (some)
documentation and test functions. It will make your code better
and it shows that you really put in the effort.
The Go test suite also allows you to incorperate example functions
which serve as documentation _and_ as tests. These functions need to
start with "Example".
Gieben Expires July 11, 2015 [Page 48]
Internet-Draft Learning Go January 2015
func ExampleEven() {
if Even(2) {
fmt.Printf("Is even\n")
}
Output: <1>
Is even
}
Those last two comments lines (1) are part of the example, "go test"
uses those to check the _generated_ output with the text in the
comments. If there is a mismatch the test fails.
5.4. Useful packages
The standard libary of Go includes a huge number of packages. It is
very enlightening to browse the "$GOROOT/src/pkg" directory and look
at the packages. We cannot comment on each package, but the
following are worth a mention:
fmt Package "fmt" implements formatted I/O with functions analogous
to C's "printf" and "scanf". The format verbs are derived from
C's but are simpler. Some verbs (%-sequences) that can be used:
%v The value in a default format. when printing structs, the plus
flag (%+v) adds field names.
%#v a Go-syntax representation of the value.
%T a Go-syntax representation of the type of the value.
io This package provides basic interfaces to I/O primitives. Its
primary job is to wrap existing implementations of such
primitives, such as those in package os, into shared public
interfaces that abstract the functionality, plus some other
related primitives.
bufio This package implements buffered I/O. It wraps an "io.Reader"
or "io.Writer" object, creating another object (Reader or Writer)
that also implements the interface but provides buffering and some
help for textual I/O.
sort The "sort" package provides primitives for sorting arrays and
user-defined collections.
strconv The "strconv" package implements conversions to and from
string representations of basic data types.
Gieben Expires July 11, 2015 [Page 49]
Internet-Draft Learning Go January 2015
os The "os" package provides a platform-independent interface to
operating system functionality. The design is Unix-like.
sync The package "sync" provides basic synchronization primitives
such as mutual exclusion locks.
flag The "flag" package implements command-line flag parsing.
encoding/json The "encoding/json" package implements encoding and
decoding of JSON objects as defined in RFC 4627 [RFC4627].
html/template Data-driven templates for generating textual output
such as HTML. Templates are executed by applying them to a data
structure. Annotations in the template refer to elements of the
data structure (typically a field of a struct or a key in a map)
to control execution and derive values to be displayed. The
template walks the structure as it executes and the "cursor" @
represents the value at the current location in the structure.
net/http The "net/http" package implements parsing of HTTP requests,
replies, and URLs and provides an extensible HTTP server and a
basic HTTP client.
unsafe The "unsafe" package contains operations that step around the
type safety of Go programs. Normally you don't need this package,
but it is worth mentioning that _unsafe_ Go programs are possible.
reflect The "reflect" package implements run-time reflection,
allowing a program to manipulate objects with arbitrary types.
The typical use is to take a value with static type "interface{}"
and extract its dynamic type information by calling "TypeOf",
which returns an object with interface type "Type". See
Section 7, Section Section 7.8.
os/exec The "os/exec" package runs external commands.
5.5. Exercises
5.5.1. Stack as package
1. See the Stack exercise. In this exercise we want to create a
separate package for that code. Create a proper package for your
stack implementation, "Push", "Pop" and the "Stack" type need to
be exported.
2. Write a simple unit test for this package. You should at least
test that a "Pop" works after a "Push".
Gieben Expires July 11, 2015 [Page 50]
Internet-Draft Learning Go January 2015
5.5.2. Answer
1. There are a few details that should be changed to make a proper
package for our stack. First, the exported functions should
begin with a capital letter and so should "Stack". The package
file is named "stack-as-package.go" and contains:
package stack
// Stack holds the items.
type Stack struct {
i int
data [10]int
}
// Push pushes an item on the stack.
func (s *Stack) Push(k int) {
s.data[s.i] = k
s.i++
}
// Pop pops an item from the stack.
func (s *Stack) Pop() (ret int) {
s.i--
ret = s.data[s.i]
return
}
2. To make the unit testing work properly you need to do some
preparations. We'll come to those in a minute. First the actual
unit test. Create a file with the name "pushpop_test.go", with
the following contents:
package stack
import "testing"
func TestPushPop(t *testing.T) {
c := new(Stack)
c.Push(5)
if c.Pop() != 5 {
t.Log("Pop doesn't give 5")
t.Fail()
}
}
For "go test" to work we need to put our package files in a directory
under "$GOPATH/src":
Gieben Expires July 11, 2015 [Page 51]
Internet-Draft Learning Go January 2015
% mkdir $GOPATH/src/stack
% cp pushpop_test.go $GOPATH/src/stack
% cp stack-as-package.go $GOPATH/src/stack
Yields:
% go test stack
ok stack 0.001s
5.5.3. Calculator
1. Create a reverse polish calculator. Use your stack package.
5.5.4. Answer
1. This is one answer:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
var reader *bufio.Reader = bufio.NewReader(os.Stdin)
var st = new(Stack)
type Stack struct {
i int
data [10]int
}
func (s *Stack) push(k int) {
if s.i+1 > 9 {
return
}
s.data[s.i] = k
s.i++
}
func (s *Stack) pop() (ret int) {
s.i--
if s.i < 0 {
s.i = 0
return
}
Gieben Expires July 11, 2015 [Page 52]
Internet-Draft Learning Go January 2015
ret = s.data[s.i]
return
}
func main() {
for {
s, err := reader.ReadString('\n')
var token string
if err != nil {
return
}
for _, c := range s {
switch {
case c >= '0' && c <= '9':
token = token + string(c)
case c == ' ':
r, _ := strconv.Atoi(token)
st.push(r)
token = ""
case c == '+':
fmt.Printf("%d\n", st.pop()+st.pop())
case c == '*':
fmt.Printf("%d\n", st.pop()*st.pop())
case c == '-':
p := st.pop()
q := st.pop()
fmt.Printf("%d\n", q-p)
case c == 'q':
return
default:
//error
}
}
}
}
6. Beyond the basics
Go has pointers but not pointer arithmetic. You cannot use a
pointer variable to walk through the bytes of a string.
-- Go For C++ Programmers, Go Authors
In this chapter we delve deeper in to the language.
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,
Gieben Expires July 11, 2015 [Page 53]
Internet-Draft Learning Go January 2015
the variables are _pass-by-value_. So, for efficiency and the
possibility to modify a passed value _in_ functions we have pointers.
You declare a pointer by prefixing the type with an '"*"': "var p
*int". Now "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 nil-value . In other languages this is often called
a NULL pointer in Go it is just "nil". To make a pointer point to
something you can use the address-of operator ("&"), which we
demonstrate here:
var p *int
fmt.Printf("%v", p) <1>
var i int <2>
p = &i <3>
fmt.Printf("%v", p) <4>
This (1) Prints "nil". Declare (2) an integer variable "i". Make
"p" point (3) to "i", i.e. take the address of "i". And this (4)
will print something like "0x7ff96b81c000a". De-referencing a
pointer is done by prefixing the pointer variable with "*".
As said, there is no pointer arithmetic, so if you write: "*p++", it
is interpreted as "(*p)++": first reference and then increment the
value.
6.1. Allocation
Go also has garbage collection, meaning that you don't have to worry
about memory deallocation.
To allocate memory Go has two primitives, "new" and "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 "new" and "make" .
6.1.1. Allocation with new
The built-in function "new" is essentially the same as its namesakes
in other languages: "new(T)" allocates zeroed storage for a new item
of type "T" and returns its address, a value of type "*T". Or in
other words, it returns a pointer to a newly allocated zero value of
type "T". This is important to remember.
Gieben Expires July 11, 2015 [Page 54]
Internet-Draft Learning Go January 2015
The documentation for "bytes.Buffer" states that "the zero value for
Buffer is an empty buffer ready to use.". Similarly, "sync.Mutex"
does not have an explicit constructor or Init method. Instead, the
zero value for a "sync.Mutex" is defined to be an unlocked mutex.
6.1.2. Allocation with make
The built-in function "make(T, args)" serves a purpose different from
"new(T)". It creates slices, maps, and channels _only_, and it
returns an initialized (not zero!) value of type "T", and not a
pointer: "*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 "nil". For slices, maps, and channels, "make" initializes
the internal data structure and prepares the value for use.
For instance, "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,
"new([]int)" returns a pointer to a newly allocated, zeroed slice
structure, that is, a pointer to a "nil" slice value. These examples
illustrate the difference between "new" and "make".
var p *[]int = new([]int) <1>
var v []int = make([]int, 100) <2>
var p *[]int = new([]int) <3>
*p = make([]int, 100, 100)
v := make([]int, 100) <4>
Allocates (1) slice structure; rarely useful. "v" (2) refers to a new
array of 100 ints. At (3) we make it unnecessarily complex, (4) is
more idiomatic.
Remember that "make" applies only to maps, slices and channels and
does not return a pointer. To obtain an explicit pointer allocate
with "new".
New allocates; make initializes.
The above two paragraphs can be summarized as:
* "new(T)" returns "*T" pointing to a zeroed "T"
Gieben Expires July 11, 2015 [Page 55]
Internet-Draft Learning Go January 2015
* "make(T)" returns an initialized "T"
And of course "make" is only used for slices, maps and channels.
6.1.3. 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
"os".
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
}
There's a lot of boiler plate in there. We can simplify it using a
_composite literal_ , which is an expression that creates a new
instance each time it is evaluated.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := File{fd, name, nil, 0}
return &f <1>
}
It is OK to return the address of a local variable (1) 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.
return &File{fd, name, nil, 0}
The items (called 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
Gieben Expires July 11, 2015 [Page 56]
Internet-Draft Learning Go January 2015
return &File{fd: fd, name: name}
As a limiting case, if a composite literal contains no fields at all,
it creates a zero value for the type. The expressions "new(File)"
and "&File{}" are equivalent. In fact the use of "new" is
discouraged.
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
"Enone", and "Einval", as long as they are distinct:
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"}
6.2. Defining your own types
Of course Go allows you to define new types, it does this with the
"type" keyword: "type foo int"
Creates a new type "foo" which acts like an "int". Creating more
sophisticated types is done with the "struct" keyword. An example
would be when we want record somebody's name ("string") and age
("int") in a single structure and make it a new type:
package main
import "fmt"
type NameAge struct {
name string // Both non exported fields.
age int
}
func main() {
a := new(NameAge)
a.name = "Pete"
a.age = 42
fmt.Printf("%v\n", a)
}
Apropos, the output of "fmt.Printf("%v\n", a)" is "&{Pete 42}"
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 ".<field name>". For example to only print the name:
Gieben Expires July 11, 2015 [Page 57]
Internet-Draft Learning Go January 2015
fmt.Printf("%s", a.name)
6.2.1. More on structure fields
As said each item in a structure is called a field (((field)). A
struct with no fields: "struct {}". Or one with four fields:
struct {
x, y int
A *[]int
F func()
}
If you omit the name for a field, you create an anonymous field , for
instance:
struct {
T1 // Field name is T1.
*T2 // Field name is T2.
P.T3 // Field name is T3.
x, y int // Field names are x and y.
}
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 Section 5 for the details.
6.2.2. Methods
If you create functions that work on your newly defined type, you can
take two routes:
1. Create a function that takes the type as an argument.
func doSomething(n1 *NameAge, n2 int) { /* */ }
2. Create a function that works on the type (see _receiver_ in
Section 4):
func (n1 *NameAge) doSomething(n2 int) { /* */ }
This is a method call, which can be used as:
var n *NameAge
n.doSomething(2)
Gieben Expires July 11, 2015 [Page 58]
Internet-Draft Learning Go January 2015
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 [go_spec]:
If "x" is addressable and "&x"'s method set contains "m", "x.m()"
is shorthand for \mbox{"(&x).m()"}.
In the above case this means that the following is _not_ an error:
var n NameAge // Not a pointer
n.doSomething(2)
Here Go will search the method list for "n" of type "NameAge", come
up empty and will then _also_ search the method list for the type
"*NameAge" and will translate this call to "(&n).doSomething(2)".
There is a subtle but major difference between the following type
declarations. Also see the Section "Type Declarations" [go_spec].
Suppose we have:
// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct { /* Mutex fields */ }
func (m *Mutex) Lock() { /* Lock impl. */ }
func (m *Mutex) Unlock() { /* Unlock impl. */ }
We now create two types in two different manners:
o "type NewMutex Mutex".
o "type PrintableMutex struct{Mutex}".
"NewMutex" is equal to "Mutex", but it _does not_ have _any_ of the
methods of "Mutex". In other words its method set is empty. But
"PrintableMutex" _has_ _inherited_ the method set from "Mutex". The
Go term for this is _embedding_ . In the words of [go_spec]:
The method set of "*PrintableMutex" contains the methods "Lock"
and "Unlock" bound to its anonymous field "Mutex".
6.3. 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: "byte()") and not all conversions are allowed.
Gieben Expires July 11, 2015 [Page 59]
Internet-Draft Learning Go January 2015
+-------+---------+---------+---------+----------+--------+---------+
| From | b | i []int | r | s string | f | i int |
| | []byte | | []rune | | flt32 | |
+-------+---------+---------+---------+----------+--------+---------+
| *To* | | | | | | |
| "[]by | . | | | "[]byte( | | |
| te" | | | | s)" | | |
| "[]in | | . | | "[]int(s | | |
| t" | | | | )" | | |
| "[]ru | | | | "[]rune( | | |
| ne" | | | | s)" | | |
| "stri | "string | "string | "string | . | | |
| ng" | (b)" | (i)" | (r)" | | | |
| "ftl3 | | | | | . | "flt32( |
| 2" | | | | | | i)" |
| "int" | | | | | "int(f | . |
| | | | | | )" | |
+-------+---------+---------+---------+----------+--------+---------+
Table 4: Valid conversions, float64 works the same as float32. Note
that float32 has been abbreviated to flt32 in this table to make it
fit on the page.
o From a "string" to a slice of bytes or runes.
mystring := "hello this is string"
byteslice := []byte(mystring)
Converts to a "byte" slice, each "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.
runeslice := []rune(mystring)
Converts to an "rune" slice, each "rune" contains a Unicode code
point. Every character from the string corresponds to one rune.
o From a slice of bytes or runes to a "string".
b := []byte{'h','e','l','l','o'} // Composite literal.
s := string(b)
i := []rune{257,1024,65}
r := string(i)
For numeric values the following conversions are defined:
o Convert to an integer with a specific (bit) length: "uint8(int)"
Gieben Expires July 11, 2015 [Page 60]
Internet-Draft Learning Go January 2015
o From floating point to an integer value: "int(float32)". This
discards the fraction part from the floating point value.
o And the other way around: "float32(int)".
6.3.1. User defined types and conversions
How can you convert between the types you have defined yourself? We
create two types here "Foo" and "Bar", where "Bar" is an alias for
"Foo":
type foo struct { int } // Anonymous struct field.
type bar foo // bar is an alias for foo.
Then we:
var b bar = bar{1} // Declare `b` to be a `bar`.
var f foo = b // Assign `b` to `f`.
Which fails on the last line with: "cannot use b (type bar) as type
foo in assignment"
This can be fixed with a conversion: "var f foo = foo(b)"
Note that converting structures that are not identical in their
fields is more difficult. Also note that converting "b" to a plain
"int" also fails; an integer is not the same as a structure
containing an integer.
6.4. Exercises
6.4.1. Map function with interfaces
1. Use the answer from the earlier map exercise but now make it
generic using interfaces. Make it at least work for ints and
strings.
6.4.2. Answer
1.
Gieben Expires July 11, 2015 [Page 61]
Internet-Draft Learning Go January 2015
package main
import "fmt"
// Define the empty interface as a type.
type e interface{}
func mult2(f e) e {
switch f.(type) {
case int:
return f.(int) * 2
case string:
return f.(string) + f.(string) + f.(string) + f.(string)
}
return f
}
func Map(n []e, f func(e) e) []e {
m := make([]e, len(n))
for k, v := range n {
m[k] = f(v)
}
return m
}
func main() {
m := []e{1, 2, 3, 4}
s := []e{"a", "b", "c", "d"}
mf := Map(m, mult2)
sf := Map(s, mult2)
fmt.Printf("%v\n", mf)
fmt.Printf("%v\n", sf)
}
6.4.3. Pointers
1. Suppose we have defined the following structure:
type Person struct {
name string
age int
}
What is the difference between the following two lines?
var p1 Person
p2 := new(Person)
Gieben Expires July 11, 2015 [Page 62]
Internet-Draft Learning Go January 2015
1. What is the difference between the following two allocations?
func Set(t *T) {
x = t
}
func Set(t T) {
x= &t
}
6.4.4. Answer
1. In first line: "var p1 Person" allocates a "Person"-_value_ to
"p1". The type of "p1" is "Person". The second line: "p2 :=
new(Person)" allocates memory and assigns a _pointer_ to "p2".
The type of "p2" is "*Person".
2. In the second function, "x" points to a new (heap-allocated)
variable "t" which contains a copy of whatever the actual argument
value is.
In the first function, "x" points to the same thing that "t" does,
which is the same thing that the actual argument points to.
So in the second function, we have an "extra" variable containing a
copy of the interesting value.
6.4.5. Linked List
1. Make use of the package "container/list" to create a (doubly)
linked list. Push the values 1, 2 and 4 to the list and then
print it.
2. Create your own linked list implementation. And perform the same
actions as above.
6.4.6. Answer
1. The following is the implementation of a program using doubly
linked lists from "container/list".
Gieben Expires July 11, 2015 [Page 63]
Internet-Draft Learning Go January 2015
package main
import (
"container/list"
"fmt"
)
func main() {
l := list.New()
l.PushBack(1)
l.PushBack(2)
l.PushBack(4)
for e := l.Front(); e != nil; e = e.Next() {
fmt.Printf("%v\n", e.Value)
}
}
2. The following is a program implementing a simple doubly linked
list supporting "int" values.
package main
import (
"errors" <1>
"fmt"
)
type Value int <2>
type Node struct { <3>
Value
prev, next *Node
}
type List struct {
head, tail *Node
}
func (l *List) Front() *Node { <4>
return l.head
}
func (n *Node) Next() *Node {
return n.next
}
func (l *List) Push(v Value) *List {
Gieben Expires July 11, 2015 [Page 64]
Internet-Draft Learning Go January 2015
n := &Node{Value: v} <5>
if l.head == nil { <6>
l.head = n
} else {
l.tail.next = n <7>
n.prev = l.tail <8>
}
l.tail = n <9>
return l
}
var errEmpty = errors.New("List is empty")
func (l *List) Pop() (v Value, err error) {
if l.tail == nil { <10>
err = errEmpty
} else {
v = l.tail.Value <11>
l.tail = l.tail.prev <12>
if l.tail == nil {
l.head = nil <13>
}
}
return v, err
}
func main() {
l := new(List)
l.Push(1)
l.Push(2)
l.Push(4)
for n := l.Front(); n != nil; n = n.Next() {
fmt.Printf("%v\n", n.Value)
}
fmt.Println()
for v, err := l.Pop(); err == nil; v, err = l.Pop() {
fmt.Printf("%v\n", v)
}
}
Gieben Expires July 11, 2015 [Page 65]
Internet-Draft Learning Go January 2015
Import (1) the packages we will need. At (2) we declare a type for
the value our list will contain, this is not strictly neccesary. And
at (3) we declare a type for the each node in our list. At (4) we
define the "Front" method for our list. When pushing, create a new
Node (5) with the provided value. If the list is empty (6), put the
new node at the head. Otherwise (7) put it at the tail and make sure
(8) the new node points back to the previously existing one. At (9)
we re-adjust tail to the newly inserted node.
In the Pop (10) method, we return an error if the list is empty. If
it is not empty (11) we save the last value. And then (12) discard
the last node from the list. Finally at (13) we make sure the list
is consistent if it becomes empty.
6.4.7. Cat
1. Write a program which mimics the Unix program "cat".
2. Make it support the "-n" flag, where each line is numbered.
3. The solution to the above question given in contains a bug. Can
you spot and fix it?
6.4.8. Answer
1. The following is implemention of "cat" which also supports a -n
flag to number each line.
Gieben Expires July 11, 2015 [Page 66]
Internet-Draft Learning Go January 2015
package main
import (
"bufio"
"flag"
"fmt"
"io" <1>
"os"
)
var numberFlag = flag.Bool("n", false, "number each line") <2>
func cat(r *bufio.Reader) { <3>
i := 1
for {
buf, e := r.ReadBytes('\n') <4>
if e == io.EOF { <5>
break
}
if *numberFlag { <6>
fmt.Fprintf(os.Stdout, "%5d %s", i, buf)
i++
} else { <7>
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
return
}
func main() {
flag.Parse()
if flag.NArg() == 0 {
cat(bufio.NewReader(os.Stdin))
}
for i := 0; i < flag.NArg(); i++ {
f, e := os.Open(flag.Arg(i))
if e != nil {
fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
os.Args[0], flag.Arg(i), e.Error())
continue
}
cat(bufio.NewReader(f))
}
}
At (1) we include all the packages we need. Here (2) we define a new
flag "n", which defaults to off. Note that we get the help (-h) for
free. Start the function (3) that actually reads the file's contents
Gieben Expires July 11, 2015 [Page 67]
Internet-Draft Learning Go January 2015
and displays it; Read one line at the time at (4). And stop (5) if
we hit the end. If we should number each line, print the line number
and then the line itself (6). Otherwise (7) we could just print the
line.
1. The bug show itself when the last line of the input does not
contain a newline. Or worse, when the input contains one line
without a closing newline nothing is shown at all. A better
solution is the following program.
Gieben Expires July 11, 2015 [Page 68]
Internet-Draft Learning Go January 2015
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
var numberFlag = flag.Bool("n", false, "number each line")
func cat(r *bufio.Reader) {
i := 1
for {
buf, e := r.ReadBytes('\n')
if e == io.EOF {
break
}
if *numberFlag {
fmt.Fprintf(os.Stdout, "%5d %s", i, buf)
i++
} else {
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
return
}
func main() {
flag.Parse()
if flag.NArg() == 0 {
cat(bufio.NewReader(os.Stdin))
}
for i := 0; i < flag.NArg(); i++ {
f, e := os.Open(flag.Arg(i))
if e != nil {
fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n",
os.Args[0], flag.Arg(i), e.Error())
continue
}
cat(bufio.NewReader(f))
}
}
Gieben Expires July 11, 2015 [Page 69]
Internet-Draft Learning Go January 2015
6.4.9. Method calls
1. Suppose we have the following program. Note the package
"container/vector" was once part of Go, but has been removed when
the "append" built-in was introduced. However, for this question
this isn't important. The package implemented a stack-like
structure, with push and pop methods. package main import
"container/vector" func main() {
k1 := vector.IntVector{}
k2 := &vector.IntVector{}
k3 := new(vector.IntVector)
k1.Push(2)
k2.Push(3)
k3.Push(4)
}
What are the types of "k1", "k2" and "k3"?
1. Now, this program compiles and runs OK. All the "Push"
operations work even though the variables are of a different
type. The documentation for "Push" says:
"func (p *IntVector) Push(x int)" Push appends x to the end of the
vector.
So the receiver has to be of type "*IntVector", why does the code
above (the Push statements) work correct then?
6.4.10. Answer
1. The type of "k1" is "vector.IntVector". Why? We use a composite
literal (the "{}"), so we get a value of that type back. The
variable "k2" is of "*vector.IntVector", because we take the
address ("&") of the composite literal. And finally "k3" has
also the type "*vector.IntVector", because "new" returns a
pointer to the type.
2. The answer is given in [go_spec] in the section "Calls", where
among other things it says:
A method call "x.m()" is valid if the method set of (the type of)
"x" contains "m" and the argument list can be assigned to the
parameter list of "m". If "x" is addressable and "\&x"'s method
set contains "m", "x.m()" is shorthand for "(\&x).m()".
Gieben Expires July 11, 2015 [Page 70]
Internet-Draft Learning Go January 2015
In other words because "k1" is addressable and "*vector.IntVector"
_does_ have the "Push" method, the call "k1.Push(2)" is translated by
Go into "(&k1).Push(2)" which makes the type system happy again (and
you too -- now you know this).
7. Interfaces
I have this phobia about having my body penetrated surgically.
You know what I mean?
-- eXistenZ, Ted Pikul
In Go, the word _interface_ is overloaded to mean several different
things. Every type has an interface, which is the _set of methods
defined_ for that type. This bit of code defines a struct type "S"
with one field, and defines two methods for "S".
type S struct { i int }
func (p *S) Get() int { return p.i }
func (p *S) Put(v int) { p.i = v }
Defining a struct and methods on it.
You can also define an interface type, which is simply a set of
methods. This defines an interface "I" with two methods:
type I interface {
Get() int
Put(int)
}
"S" is a valid _implementation_ for interface "I", because it defines
the two methods which "I" requires. Note that this is true even
though there is no explicit declaration that "S" implements "I".
A Go program can use this fact via yet another meaning of interface,
which is an interface value:
func f(p I) { <1>
fmt.Println(p.Get()) <2>
p.Put(1) <3>
}
At (1) we declare a function that takes an interface type as the
argument. Because "p" implements "I", it _must_ have the "Get()"
method, which we call at (2). And the same holds true for the
"Put()" method at (3). Because "S" implements "I", we can call the
Gieben Expires July 11, 2015 [Page 71]
Internet-Draft Learning Go January 2015
function "f" passing in a pointer to a value of type "S": "var s S;
f(&s)"
The reason we need to take the address of "s", rather than a value of
type "S", is because we defined the methods on "s" to operate on
pointers, see the definition in the code above. This is not a
requirement -- we could have defined the methods to take values --
but then the "Put" method would not work as expected.
The fact that you do not need to declare whether or not a type
implements an interface means that Go implements a form of duck
typing [duck_typing]. This is not pure duck typing, because when
possible the Go compiler will statically check whether the type
implements the interface. However, Go does have a purely dynamic
aspect, in that you can convert from one interface type to another.
In the general case, that conversion is checked at run time. If the
conversion is invalid -- if the type of the value stored in the
existing interface value does not satisfy the interface to which it
is being converted -- the program will fail with a run time error.
Interfaces in Go are similar to ideas in several other programming
languages: pure abstract virtual base classes in C++, typeclasses in
Haskell or duck typing in Python. However there is no other language
which combines interface values, static type checking, dynamic run
time conversion, and no requirement for explicitly declaring that a
type satisfies an interface. The result in Go is powerful, flexible,
efficient, and easy to write.
7.1. Which is what?
Let's define another type "R" that also implements the interface "I":
type R struct { i int }
func (p *R) Get() int { return p.i }
func (p *R) Put(v int) { p.i = v }
The function "f" can now accept variables of type "R" and "S".
Suppose you need to know the actual type in the function "f". In Go
you can figure that out by using a type switch ((type switch)).
Gieben Expires July 11, 2015 [Page 72]
Internet-Draft Learning Go January 2015
func f(p I) {
switch t := p.(type) { <1>
case *S: <2>
case *R: <3>
case S: <4>
case R: <5>
default: <6>
}
}
At (1) we use the type switch, note that the ".(type)" syntax in
_only_ valid within a "switch" statement. We store the type in the
variable "t". The subsequent cases (2, 3, 4, 5) each check for a
different _actual_ type. And we can even have a "default" (6)
clause.
A type switch isn't the only way to discover the type at _run-time_.
if t, ok := something.(I); ok { <1>
...
}
You can also use a "comma, ok" form (1) to see if an interface type
implements a specific interface. If "ok" is true, "t" will hold the
type of "something". When you are sure a variable implements an
interface you can use: "t := something.(I)" .
7.2. Empty interface
Since every type satisfies the empty interface: "interface{}". We
can create a generic function which has an empty interface as its
argument:
func g(something interface{}) int {
return something.(I).Get()
}
The "return something.(I).Get()" is the tricky bit in this function.
The value "something" has type "interface{}", meaning no guarantee of
any methods at all: it could contain any type. The ".(I)" is a type
assertion which converts "something" to an interface of type "I". If
we have that type we can invoke the "Get()" function. So if we
create a new variable of the type "*S", we can just call "g()",
because "*S" also implements the empty interface.
s = new(S)
fmt.Println(g(s));
Gieben Expires July 11, 2015 [Page 73]
Internet-Draft Learning Go January 2015
The call to "g" will work fine and will print 0. If we however
invoke "g()" with a value that does not implement "I" we have a
problem:
i :=
fmt.Println(g(i))
This compiles, but when we run this we get slammed with: "panic:
interface conversion: int is not main.I: missing method Get".
Which is completely true, the built-in type "int" does not have a
"Get()" method.
7.3. Methods
Methods are functions that have a receiver (see Section 4). You can
define methods on any type (except on non-local types, this includes
built-in types: the type "int" can not have methods). You can
however make a new integer type with its own methods. For example:
type Foo int
func (self Foo) Emit() {
fmt.Printf("%v", self)
}
type Emitter interface {
Emit()
}
Doing this on non-local (types defined in other packages) types
yields an error "cannot define new methods on non-local type int".
7.4. Methods on interface types
An interface defines a set of methods. A method contains the actual
code. In other words, an interface is the definition and the methods
are the implementation. So a receiver can not be an interface type,
doing so results in a "invalid receiver type ..." compiler error.
The authoritative word from the language spec [go_spec]:
The receiver type must be of the form "T" or "*T" where "T" is a
type name. "T" is called the receiver base type or just base
type. The base type must not be a pointer or interface type and
must be declared in the same package as the method.
Creating a pointer to an interface value is a useless action in
Go. It is in fact illegal to create a pointer to an interface
Gieben Expires July 11, 2015 [Page 74]
Internet-Draft Learning Go January 2015
value. The release notes for an earlier Go release that made them
illegal leave no room for doubt:
The language change is that uses of pointers to interface
values no longer automatically de-reference the pointer. A
pointer to an interface value is more often a beginner's bug
than correct code.
7.5. Interface names
By convention, one-method interfaces are named by the method name
plus the _-er_ suffix: Read_er_, Writ_er_, Formatt_er_ etc.
There are a number of such names and it's productive to honor them
and the function names they capture. "Read", "Write", "Close",
"Flush", "String" and so on have canonical signatures and meanings.
To avoid confusion, don't give your method one of those names unless
it has the same signature and meaning. Conversely, if your type
implements a method with the same meaning as a method on a well-known
type, give it the same name and signature; call your string-converter
method "String" not "ToString".
7.6. A sorting example
Recall the Bubblesort exercise, where we sorted an array of integers:
func bubblesort(n []int) {
for i := 0; i < len(n)-1; i++ {
for j := i + 1; j < len(n); j++ {
if n[j] < n[i] {
n[i], n[j] = n[j], n[i]
}
}
}
}
A version that sorts strings is identical except for the signature of
the function: "func bubblesortString(n []string) { /* ... */ }" .
Using this approach would lead to two functions, one for each type.
By using interfaces we can make this more generic. Let's create a
new function that will sort both strings and integers, something
along the lines of this non-working example:
Gieben Expires July 11, 2015 [Page 75]
Internet-Draft Learning Go January 2015
func sort(i []interface{}) { <1>
switch i.(type) { <2>
case string: <3>
...
case int:
...
}
return /* ... */ <4>
}
Our function will receive a slice of empty interfaces at (1). We
then (2) use a type switch to find out what the actual type of the
input is. And then (3) then sort accordingly. And, when done,
return (4) the sorted slice.
But when we call this function with "sort([]int{1, 4, 5})", it fails
with: "cannot use i (type []int) as type []interface in function
argument"
This is because Go can not easily convert to a _slice_ of interfaces.
Just converting to an interface is easy, but to a slice is much more
costly. To keep a
The full mailing list discussion on this subject can be found at
[go_nuts_interfaces]. long story short: Go does not (implicitly)
convert slices for you.
So what is the Go way of creating such a "generic" function? Instead
of doing the type inference ourselves with a type switch, we let Go
do it implicitly: The following steps are required:
o Define an interface type (called "Sorter" here) with a number of
methods needed for sorting. We will at least need a function to
get the length of the slice, a function to compare two values and
a swap function.
type Sorter interface {
Len() int // len() as a method.
Less(i, j int) bool // p[j] < p[i] as a method.
Swap(i, j int) // p[i], p[j] = p[j], p[i] as a method.
}
o Define new types for the slices we want to sort. Note that we
declare slice types:
type Xi []int
type Xs []string
Gieben Expires July 11, 2015 [Page 76]
Internet-Draft Learning Go January 2015
o Implementation of the methods of the "Sorter" interface. For
integers:
func (p Xi) Len() int {return len(p)}
func (p Xi) Less(i int, j int) bool {return p[j] < p[i]}
func (p Xi) Swap(i int, j int) {p[i], p[j] = p[j], p[i]}
And for strings:
func (p Xs) Len() int {return len(p)}
func (p Xs) Less(i int, j int) bool {return p[j] < p[i]}
func (p Xs) Swap(i int, j int) {p[i], p[j] = p[j], p[i]}
o Write a _generic_ Sort function that works on the "Sorter"
interface.
func Sort(x Sorter) { <1>
for i := 0; i < x.Len() - 1; i++ { <2>
for j := i + 1; j < x.Len(); j++ {
if x.Less(i, j) {
x.Swap(i, j)
}
}
}
}
At (1) "x" is now of the "Sorter" type and using de defined
methods for this interface we implement Bubblesort at (2).
Now we can use our _generic_ "Sort" function as follows:
ints := Xi{44, 67, 3, 17, 89, 10, 73, 9, 14, 8}
strings := Xs{"nut", "ape", "elephant", "zoo", "go"}
Sort(ints)
fmt.Printf("%v\n", ints)
Sort(strings)
fmt.Printf("%v\n", strings)
7.7. Listing interfaces in interfaces
Take a look at the following example of an interface definition, this
one is from the package "container/heap":
Gieben Expires July 11, 2015 [Page 77]
Internet-Draft Learning Go January 2015
type Interface interface {
sort.Interface
Push(x interface{})
Pop() interface{}
}
Here another interface is listed inside the definition of
"heap.Interface", this may look odd, but is perfectly valid, remember
that on the surface an interface is nothing more than a listing of
methods. "sort.Interface" is also such a listing, so it is perfectly
legal to include it in the interface.
7.8. Introspection and reflection
In the following example we want to look at the "tag" (here named
"namestr") defined in the type definition of "Person". To do this we
need the "reflect" package (there is no other way in Go). Keep in
mind that looking at a tag means going back to the _type_ definition.
So we use the "reflect" package to figure out the type of the
variable and _then_ access the tag.
type Person struct {
name string "namestr"
age int
}
func ShowTag(i interface{}) { <1>
switch t := reflect.TypeOf(i); t.Kind() {
case reflect.Ptr: <2>
tag := t.Elem().Field(0).Tag
<3> <4> <5>
Introspection using reflection.
We are calling "ShowTag" at (1) with a "*Person", so at (2) we're
expecting a "reflect.Ptr". We are dealing with a "Type" (3) and
according to the documentation :
Elem returns a type's element type. It panics if the type's Kind
is not Array, Chan, Map, Ptr, or Slice.
So on "t" we use "Elem()" to get the value the pointer points to. We
have now dereferenced the pointer and are "inside" our structure. We
then (4) use "Field(0)" to access the zeroth field.
The struct "StructField" has a "Tag" member which returns the tag-
name as a string. So on the 0^{th} field we can unleash ".Tag" (5)
to access this name: "Field(0).Tag". This gives us "namestr".
Gieben Expires July 11, 2015 [Page 78]
Internet-Draft Learning Go January 2015
To make the difference between types and values more clear, take a
look at the following code:
func show(i interface{}) {
switch t := i.(type) {
case *Person:
t := reflect.TypeOf(i) <1>
v := reflect.ValueOf(i) <2>
tag := t.Elem().Field(0).Tag <3>
name := v.Elem().Field(0).String() <4>
}
}
Reflection and the type and value.
At (1) we create "t" the type data of "i", and "v" gets the actual
values at (2). Here at (3) we want to get to the "tag". So we need
"Elem()" to redirect the pointer, access the first field and get the
tag. Note that we operate on "t" a "reflect.Type". Now (4) we want
to get access to the _value_ of one of the members and we employ
"Elem()" on "v" to do the redirection. we have "arrived" at the
structure. Then we go to the first field "Field(0)" and invoke the
"String()" method on it.
fig/reflection.png
Peeling away the layers using reflection. [6]
Peeling away the layers using reflection. Going from a *Person via
Elem using the methods described in go doc reflect to get the actual
string contained within.
Setting a value works similarly as getting a value, but only works on
_exported_ members. Again some code:
Gieben Expires July 11, 2015 [Page 79]
Internet-Draft Learning Go January 2015
type Person struct {
name string
age int
}
func Set(i interface{}) {
switch i.(type) {
case *Person:
r := reflect.ValueOf(i)
r.Elem(0).Field(0).SetString("Albert Einstein")
}
}
Reflect with private member.
type Person struct {
Name string
age int
}
func Set(i interface{}) {
switch i.(type) {
case *Person:
r := reflect.ValueOf(i)
r.Elem().Field(0).SetString("Albert Einstein")
}
}
Reflect with public member.
The first program compiles and runs, but when you run it, you are
greeted with a stack trace and a _run time_ error: "panic:
reflect.Value.SetString using value obtained using unexported field".
The code on the right works OK and sets the member "Name" to "Albert
Einstein". Of course this only works when you call "Set()" with a
pointer argument.
7.9. Exercises
7.9.1. Interfaces and max()
In the maximum exercise we created a max function that works on a
slice of integers. The question now is to create a program that
shows the maximum number and that works for both integers and floats.
Try to make your program as generic as possible, although that is
quite difficult in this case.
Gieben Expires July 11, 2015 [Page 80]
Internet-Draft Learning Go January 2015
7.9.2. Answer
The following program calculates a maximum. It is as generic as you
can get with Go.
package main
import "fmt"
func Less(l, r interface{}) bool { <1>
switch l.(type) {
case int:
if _, ok := r.(int); ok {
return l.(int) < r.(int) <2>
}
case float32:
if _, ok := r.(float32); ok {
return l.(float32) < r.(float32) <3>
}
}
return false
}
func main() {
var a, b, c int = 5, 15, 0
var x, y, z float32 = 5.4, 29.3, 0.0
if c = a; Less(a, b) { <4>
c = b
}
if z = x; Less(x, y) { <5>
z = y
}
fmt.Println(c, z)
}
We could have chosen to make the return type of this (1) function an
"interface{}", but that would mean that a caller would always have to
do a type assertion to extract the actual type from the interface.
At (2) we compare the parameters. All parameters are confirmed to be
integers, so this is legit. And at (3) we do the some for floats.
At (4, 5) we get the maximum value for "a", "b" and "x" and "y".
7.9.3. Pointers and reflection
One of the last paragraphs in section "\titleref{sec:introspection
and reflection}" on page \pageref{sec:introspection and reflection},
has the following words:
Gieben Expires July 11, 2015 [Page 81]
Internet-Draft Learning Go January 2015
The code on the right works OK and sets the member "Name" to
"Albert Einstein". Of course this only works when you call
"Set()" with a pointer argument.
Why is this the case?
7.9.4. Answer
When called with a non-pointer argument the variable is a copy (call-
by-value). So you are doing the reflection voodoo on a copy. And
thus you are _not_ changing the original value, but only this copy.
8. Concurrency
* Parallelism is about performance.
* Concurrency is about program design.
-- Google I/O 2010, Rob Pike
In this chapter we will show off Go's ability for concurrent
programming using channels and goroutines. Goroutines are the
central entity in Go's ability for concurrency.
But what _is_ a goroutine, from [effective_go]:
They're called goroutines because the existing terms -- threads,
coroutines, processes, and so on -- convey inaccurate
connotations. A goroutine has a simple model: _it is a function
executing in parallel with other goroutines in the same address
space_. It is lightweight, costing little more than the allocation
of stack space. And the stacks start small, so they are cheap,
and grow by allocating (and freeing) heap storage as required.
A goroutine is a normal function, except that you start it with the
keyword "go".
ready("Tea", 2) // Normal function call.
go ready("Tea", 2) // ... as goroutine.
Gieben Expires July 11, 2015 [Page 82]
Internet-Draft Learning Go January 2015
func ready(w string, sec int) {
time.Sleep(time.Duration(sec) * time.Second)
fmt.Println(w, "is ready!")
}
func main() {
go ready("Tea", 2) <1>
go ready("Coffee", 1) <2>
fmt.Println("I'm waiting")
time.Sleep(5 * time.Second) <3>
}
Go routines in action.
The following idea for a program was taken from [go_course_day3]. We
run a function as two goroutines, the goroutines wait for an amount
of time and then print something to the screen. At (1, 2) we start
the goroutines. The "main" function waits long enough at (3), so
that both goroutines will have printed their text. Right now we wait
for 5 seconds, but in fact we have no idea how long we should wait
until all goroutines have exited. This outputs:
I'm waiting // Right away
Coffee is ready! // After 1 second
Tea is ready! // After 2 seconds
If we did not wait for the goroutines (i.e. remove thei last line at
<2>) the program would be terminated immediately and any running
goroutines would _die with it_.
To fix this we need some kind of mechanism which allows us to
communicate with the goroutines. This mechanism is available to us
in the form of channels . A channel can be compared to a two-way pipe
in Unix shells: you can send to and receive values from it. Those
values can only be of a specific type: the type of the channel. If
we define a channel, we must also define the type of the values we
can send on the channel. Note that we must use "make" to create a
channel:
ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{})
Makes "ci" a channel on which we can send and receive integers, makes
"cs" a channel for strings and "cf" a channel for types that satisfy
the empty interface. Sending on a channel and receiving from it, is
done with the same operator: "<-".
Gieben Expires July 11, 2015 [Page 83]
Internet-Draft Learning Go January 2015
Depending on the operands it figures out what to do, "ci <- 1",
_Send_ the integer 1 to the channel "ci". "<-ci",{_Receive_ an
integer from the channel "ci". "i := <-ci",_Receive_ from the channel
"ci" and store it in "i".
Let's put this to use.
var c chan int <1>
func ready(w string, sec int) {
time.Sleep(time.Duration(sec) * time.Second)
fmt.Println(w, "is ready!")
c <- 1 <2>
}
func main() {
c = make(chan int) <3>
go ready("Tea", 2) <4>
go ready("Coffee", 1) <5>
fmt.Println("I'm waiting, but not too long")
<-c <6>
<-c <7>
}
At (1) we declare "c" to be a variable that is a channel of ints.
That is: this channel can move integers. Note that this variable is
global so that the goroutines have access to it. At (2) in the
"ready" function we send the integer 1 on the channel. In our "main"
function we initialize "c" at (3) and start our goroutines (4, 5).
At (6, 7) we Wait until we receive a value from the channel, the
value we receive is discarded. We have started two goroutines, so we
expect two values to receive.
There is still some remaining ugliness; we have to read twice from
the channel (6, 7)). This is OK in this case, but what if we don't
know how many goroutines we started? This is where another Go built-
in comes in: "select" . With "select" you can (among other things)
listen for incoming data on a channel.
Using "select" in our program does not really make it shorter,
because we run too few go-routines. We remove last lines and replace
them with the following:
Gieben Expires July 11, 2015 [Page 84]
Internet-Draft Learning Go January 2015
L: for {
select {
case <-c:
i++
if i > 1 {
break L
}
}
}
We will now wait as long as it takes. Only when we have received
more than one reply on the channel "c" will we exit the loop "L".
8.1. Make it run in parallel
While our goroutines were running concurrently, they were not running
in parallel. When you do not tell Go anything there can only be one
goroutine running at a time. With "runtime.GOMAXPROCS(n)" you can
set the number of goroutines that can run in parallel. From the
documentation:
GOMAXPROCS sets the maximum number of CPUs that can be executing
simultaneously and returns the previous setting. If n < 1, it
does not change the current setting. _This call will go away when
the scheduler improves._
If you do not want to change any source code you can also set an
environment variable "GOMAXPROCS" to the desired value.
8.2. More on channels
When you create a channel in Go with "ch := make(chan bool)", an
unbuffered channel for bools is created. What does this mean for
your program? For one, if you read ("value := <-ch") it will block
until there is data to receive. Secondly anything sending ("ch<-5")
will block until there is somebody to read it. Unbuffered channels
make a perfect tool for synchronizing multiple goroutines.
But Go allows you to specify the buffer size of a channel, which is
quite simply how many elements a channel can hold. "ch := make(chan
bool, 4)", creates a buffered channel of bools that can hold 4
elements. The first 4 elements in this channel are written without
any blocking. When you write the 5^th^ element, your code _will_
block, until another goroutine reads some elements from the channel
to make room.
In conclusion, the following is true in Go:
Gieben Expires July 11, 2015 [Page 85]
Internet-Draft Learning Go January 2015
\textsf{ch := make(chan type, value)} \left\{ \begin{array}{ll} value
== 0 & \rightarrow \textsf{unbuffered} \\ value > 0 & \rightarrow
\textsf{buffer }{} value{} \textsf{ elements} \end{array} \right.
When a channel is closed the reading side needs to know this. The
following code will check if a channel is closed.
x, ok = <-ch
Where "ok" is set to "true" the channel is not closed _and_ we've
read something. Otherwise "ok" is set to "false". In that case the
channel was closed.
8.3. Exercises
8.3.1. Channels
1. Modify the program you created in exercise Q\ref{ex:for-loop} to
use channels, in other words, the function called in the body
should now be a goroutine and communication should happen via
channels. You should not worry yourself on how the goroutine
terminates.
2. There are a few annoying issues left if you resolve question 1
above. One of the problems is that the goroutine isn't neatly
cleaned up when "main.main()" exits. And worse, due to a race
condition between the exit of "main.main()" and "main.shower()"
not all numbers are printed. It should print up until 9, but
sometimes it prints only to 8. Adding a second quit-channel you
can remedy both issues. Do this.
8.3.2. Answer
1. A possible program is: \lstinputlisting[label=go-
chan,caption=Channels in Go,numbers=right]{ex-channels/src/for-
chan.go}
We start of in the usual way, then at line 6 we create a new channel
of ints. In the next line we fire off the function "shower" with the
"ch" variable as it argument, so that we may communicate with it.
Next we start our for-loop (lines 8-10) and in the loop we send (with
"<-") our number to the function (now a goroutine) "shower".
In the function "shower" we wait (as this blocks) until we receive a
number (line 15). Any received number is printed (line 16) and then
continue the endless loop started on line 14.
Gieben Expires July 11, 2015 [Page 86]
Internet-Draft Learning Go January 2015
1. An answer is \lstinputlisting[label=go-quit-chan,caption=Adding
an extra quit channel,numbers=right]{ex-channels/src/for-quit-
chan.go}
On line 20 we read from the quit channel and we discard the value we
read. We could have used "q := <-quit", but then we would have used
the variable only once --- which is illegal in Go. Another trick you
might have pulled out of your hat may be: "_ = <-quit". This is
valid in Go, but idomatic Go is the one given on line 20.
8.3.3. Fibonacci II
This is the same exercise as the one given page \pageref{ex:fibonaci}
in exercise \ref{ex:fibonaci}. For completeness the complete
question:
The Fibonacci sequence starts as follows: 1, 1, 2, 3, 5, 8, 13,
\ldots Or in mathematical terms: x_1 = 1; x_2 = 1; x_n = x_{n-1} +
x_{n-2}\quad\forall n > 2 .
Write a function that takes an "int" value and gives that many
terms of the Fibonacci sequence.
_But_ now the twist: You must use channels.
8.3.4. Answer
The following program calculates the Fibonacci numbers using
channels.
Gieben Expires July 11, 2015 [Page 87]
Internet-Draft Learning Go January 2015
package main
import "fmt"
func dup3(in <-chan int) (<-chan int, <-chan int, <-chan int) {
a, b, c := make(chan int, 2), make(chan int, 2), make(chan int, 2)
go func() {
for {
x := <-in
a <- x
b <- x
c <- x
}
}()
return a, b, c
}
func fib() <-chan int {
x := make(chan int, 2)
a, b, out := dup3(x)
go func() {
x <- 0
x <- 1
<-a
for {
x <- <-a+<-b
}
}()
return out
}
func main() {
x := fib()
for i := 0; i < 10; i++ {
fmt.Println(<-x)
}
}
// See sdh33b.blogspot.com/2009/12/fibonacci-in-go.html
9. Communication
Good communication is as stimulating as black coffee, and just as
hard to sleep after.
-- , Anne Morrow Lindbergh
In this chapter we are going to look at the building blocks in Go for
communicating with the outside world. We will look at files,
Gieben Expires July 11, 2015 [Page 88]
Internet-Draft Learning Go January 2015
directories, networking and executing other programs. Central to
Go's I/O are the interfaces "io.Reader" and "io.Writer". The
"io.Reader" interface specifies one method "Read(p []byte) (n int,
err err)".
Reading from (and writing to) files is easy in Go. This program only
uses the "os" package to read data from the file "/etc/passwd".
package main
import (
"log"
"os"
)
func main() {
buf := make([]byte, 1024)
f, e := os.Open("/etc/passwd") <1>
if e != nil {
log.Fatalf(e)
}
defer f.Close() <2>
for {
n, e := f.Read(buf) <3>
if e != nil {
log.Fatalf(e) <4>
}
if n == 0 { <5>
break
}
os.Stdout.Write(buf[:n]) <6>
}
}
We open the file at (1) with "os.Open" that returns a "*os.File"
"*os.File" implements "io.Reader" and "io.Writer" interface. After
the "Open" we directly put the "f.Close()" which we defer until the
function return. At (3) we call "Read" on "f" and read up to 1024
bytes at the time. If anything fails we bail out at (4). If the
number of bytes read is 0 we've read the end of the file (5). And at
(6) we output the buffer to standard output.
If you want to use buffered I/O there is the "bufio" package:
Gieben Expires July 11, 2015 [Page 89]
Internet-Draft Learning Go January 2015
package main
import (
"bufio"
"log"
"os"
)
func main() {
buf := make([]byte, 1024)
f, e := os.Open("/etc/passwd") <1>
if e != nil {
log.Fatalf(e)
}
defer f.Close()
r := bufio.NewReader(f) <2>
w := bufio.NewWriter(os.Stdout)
defer w.Flush() <3>
for {
n, e := r.Read(buf) <4>
if e != nil {
log.Fatalf(e)
}
if n == 0 {
break
}
w.Write(buf[0:n]) <5>
}
}
Again, we open (1) the file. Then at (2) we Turn "f" into a buffered
"Reader". "NewReader" expects an "io.Reader", so you this will work.
Then at (4) we read and at (5) we write. We also call "Flush()" at
(3) to flush all output. This entire program could be optimized
further by using "io.Copy".
9.1. io.Reader
As mentioned above the "io.Reader" is an important interface in the
language Go. A lot (if not all) functions that need to read from
something take an "io.Reader" as input. To fulfill the interface a
type needs to implement that one method. The writing side
"io.Writer", has the "Write" method.
If you think of a new type in your program or package and you make it
fulfill the "io.Reader" or "io.Writer" interface, _the whole standard
Go library can be used_ on that type!
Gieben Expires July 11, 2015 [Page 90]
Internet-Draft Learning Go January 2015
9.2. Some examples
The previous program reads a file in its entirety, but a more common
scenario is that you want to read a file on a line-by-line basis.
The following snippet shows a way to do just that (we're discarding
the error returned from "os.Open" here to keep the examples smaller
-- don't ever do this in real life code).
f, _ := os.Open("/etc/passwd"); defer f.Close()
r := bufio.NewReader(f) //<1>
s, ok := r.ReadString('\n') //<2>
//<3>
At <1> make "f" a "bufio" to have access to the "ReadString" method.
Then at <2> we read a line from the input, "s" now holds to string
which we can manipulate with, for instance, the "strings" package.
A more robust method (but slightly more complicated) is "ReadLine",
see the documentation of the "bufio" package.
A common scenario in shell scripting is that you want to check if a
directory exists and if not, create one.
if [ ! -e name ]; then if f, e := os.Stat("name"); e != nil {
mkdir name os.Mkdir("name", 0755)
else } else {
# error // error
fi }
The similarity between these two examples (and with other scripting
languages) have prompted comments that Go has a "script"-like feel to
it, i.e. programming in Go can be compared to programming in an
interpreted language (Python, Ruby, Perl or PHP).
9.3. Command line arguments
Arguments from the command line are available inside your program via
the string slice "os.Args", provided you have imported the package
"os". The "flag" package has a more sophisticated interface, and
also provides a way to parse flags. Take this example from a DNS
query tool:
Gieben Expires July 11, 2015 [Page 91]
Internet-Draft Learning Go January 2015
dnssec := flag.Bool("dnssec", false, "Request DNSSEC records") <1>
port := flag.String("port", "53", "Set the query port") <2>
flag.Usage = func() { <3>
fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] [name ...]\n", os.Args[0])
flag.PrintDefaults() <4>
}
flag.Parse() <5>
At (1) we define a "bool" flag "-dnssec". Note that this function
returns a _pointer_ to the value, the "dnssec" is now a pointer to a
"bool". At (2) we define an "strings" flag. Then at (3) we
_redefine_ the "Usage" variable of the flag package so we can add
some extra text. The "PrintDefaults" at (4, 5) will output the
default help for the flags that are defined. Note even without
redefining a "flag.Usage" a "-h" is support and will just output the
help text for each of the flags. Finally at (4, 5) we call "Parse"
that parses the command line and fill the fill the variables.
After the flags have been parsed you can used them: "if *dnssec { ...
}"
9.4. Executing commands
The "os/exec" package has functions to run external commands, and is
the premier way to execute commands from within a Go program. It
works by defining a "*exec.Cmd" structure for which it defines a
number of methods. Let's execute "ls -l":
import "os/exec"
cmd := exec.Command("/bin/ls", "-l")
err := cmd.Run()
The above example just runs "ls -l" without doing anything with the
returned data, capturing the standard output from a command is done
as follows:
cmd := exec.Command("/bin/ls", "-l")
buf, err := cmd.Output()
And "buf" is byte slice, that you can further use in your program.
9.5. Networking
All network related types and functions can be found in the package
"net". One of the most important functions in there is "Dial". When
you "Dial" into a remote system the function returns a "Conn"
interface type, which can be used to send and receive information.
Gieben Expires July 11, 2015 [Page 92]
Internet-Draft Learning Go January 2015
The function "Dial" neatly abstracts away the network family and
transport. So IPv4 or IPv6, TCP or UDP can all share a common
interface.
Dialing a remote system (port 80) over TCP, then UDP and lastly TCP
over IPv6 looks like this:
conn, e := Dial("tcp", "192.0.32.10:80")
conn, e := Dial("udp", "192.0.32.10:80")
conn, e := Dial("tcp", "[2620:0:2d0:200::10]:80")
If there were no errors (returned in "e"), you can use "conn" to read
and write. And "conn" implements the "io.Reader" and "io.Writer"
interface.
But these are the low level nooks and crannies, you will almost
always use higher level packages, such as the "http" package. For
instance a simple Get for http:
package main
import (
"fmt"
"http"
"io/ioutil"
)
func main() {
r, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
fmt.Printf("%s\n", err.String())
return
}
b, err := ioutil.ReadAll(r.Body)
r.Body.Close()
if err == nil {
fmt.Printf("%s", string(b))
}
}
9.6. Exercises
9.6.1. Finger daemon
Write a finger daemon that works with the finger(1) command.
From the Debian [7] package description:
Gieben Expires July 11, 2015 [Page 93]
Internet-Draft Learning Go January 2015
Fingerd is a simple daemon based on RFC 1196 [RFC1196] that
provides an interface to the "finger" program at most network
sites. The program is supposed to return a friendly, human-
oriented status report on either the system at the moment or a
particular person in depth.
Stick to the basics and only support a username argument. If the
user has a ".plan" file show the contents of that file. So your
program needs to be able to figure out:
o Does the user exist?
o If the user exists, show the contents of the ".plan" file.
9.6.2. Answer
This solution is from Fabian Becker.
package main
import (
"bufio"
"errors"
"flag"
"io/ioutil"
"net"
"os/user"
)
func main() {
flag.Parse()
ln, err := net.Listen("tcp", ":79")
if err != nil {
panic(err)
}
for {
conn, err := ln.Accept()
if err != nil {
continue
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
usr, _, _ := reader.ReadLine()
Gieben Expires July 11, 2015 [Page 94]
Internet-Draft Learning Go January 2015
if info, err := getUserInfo(string(usr)); err != nil {
conn.Write([]byte(err.Error()))
} else {
conn.Write(info)
}
}
func getUserInfo(usr string) ([]byte, error) {
u, e := user.Lookup(usr)
if e != nil {
return nil, e
}
data, err := ioutil.ReadFile(u.HomeDir + ".plan")
if err != nil {
return data, errors.New("User doesn't have a .plan file!\n")
}
return data, nil
}
9.6.3. Echo server
Write a simple echo server. Make it listen to TCP port number 8053
on localhost. It should be able to read a line (up to the newline),
echo back that line and then close the connection.
Make the server concurrent so that every request is taken care of in
a separate goroutine.
9.6.4. Answer
A simple echo server might be:
Gieben Expires July 11, 2015 [Page 95]
Internet-Draft Learning Go January 2015
package main
import (
"bufio"
"fmt"
"net"
)
func main() {
l, err := net.Listen("tcp", "127.0.0.1:8053")
if err != nil {
fmt.Printf("Failure to listen: %s\n", err.Error())
}
for {
if c, err := l.Accept(); err == nil {
Echo(c)
}
}
}
func Echo(c net.Conn) {
defer c.Close()
line, err := bufio.NewReader(c).ReadString('\n')
if err != nil {
fmt.Printf("Failure to read: %s\n", err.Error())
return
}
_, err = c.Write([]byte(line))
if err != nil {
fmt.Printf("Failure to write: %s\n", err.Error())
return
}
}
When started you should see the following:
% nc 127.0.0.1 8053
Go is *awesome*
Go is *awesome*
To make the connection handling concurrent we _only need to change
one line_ in our echo server, the line:
if c, err := l.Accept(); err == nil { Echo(c) }
becomes:
if c, err := l.Accept(); err == nil { go Echo(c) }
Gieben Expires July 11, 2015 [Page 96]
Internet-Draft Learning Go January 2015
{.exercise data-difficulty="0" Word and letter count
Write a small program that reads text from standard input and
performs the following actions:
o Count the number of characters (including spaces).
o Count the number of words.
o Count the numbers of lines
In other words implement wc(1) (check you local manual page), however
you only have to read from standard input.
9.6.5. Answer
The following program is an implementation of wc(1).
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
var chars, words, lines int
r := bufio.NewReader(os.Stdin) <1>
for {
switch s, ok := r.ReadString('\n'); true { <2>
case ok != nil: <3>
fmt.Printf("%d %d %d\n", chars, words, lines)
return
default: <4>
chars += len(s)
words += len(strings.Fields(s))
lines++
}
}
}
At (1) we create a new reader that reads from standard input, we then
read from the input at (2). And at (3) we check the value of "ok"
and if we received an error, we assume it was because of a EOF, So we
print the current values;. Otherwise (4) we count the charaters,
words and increment the number lines.
Gieben Expires July 11, 2015 [Page 97]
Internet-Draft Learning Go January 2015
9.6.6. Uniq
Write a Go program that mimics the function of the Unix "uniq"
command. This program should work as follows, given a list with the
following items:
'a' 'b' 'a' 'a' 'a' 'c' 'd' 'e' 'f' 'g'
it should print only those item which don't have the same successor:
'a' 'b' 'a' 'c' 'd' 'e' 'f'
The next listing is a Perl implementation of the algorithm.
#!/usr/bin/perl
my @a = qw/a b a a a c d e f g/;
print my $first = shift @a;
foreach (@a) {
if ($first ne $_) { print; $first = $_; }
}
9.6.7. Answer
The following is a "uniq" implementation in Go.
package main
import "fmt"
func main() {
list := []string{"a", "b", "a", "a", "c", "d", "e", "f"}
first := list[0]
fmt.Printf("%s ", first)
for _, v := range list[1:] {
if first != v {
fmt.Printf("%s ", v)
first = v
}
}
}
9.6.8. Quine
A _Quine_ is a program that prints itself. Write a Quine in Go.
Gieben Expires July 11, 2015 [Page 98]
Internet-Draft Learning Go January 2015
9.6.9. Answer
This solution is from Russ Cox. It was posted to the Go Nuts
mailing list.
/* Go quine */
package main
import "fmt"
func main() {
fmt.Printf("%s%c%s%c\n", q, 0x60, q, 0x60)
}
var q = `/* Go quine */
package main
import "fmt"
func main() {
fmt.Printf("%s%c%s%c\n", q, 0x60, q, 0x60)
}
var q = `
9.6.10. Processes
Write a program that takes a list of all running processes and prints
how many child processes each parent has spawned. The output should
look like:
Pid 0 has 2 children: [1 2]
Pid 490 has 2 children: [1199 26524]
Pid 1824 has 1 child: [7293]
o For acquiring the process list, you'll need to capture the output
of "ps -e -opid,ppid,comm". This output looks like:
PID PPID COMMAND
9024 9023 zsh
19560 9024 ps
o If a parent has one child you must print "child", if there is more
than one print "children".
o The process list must be numerically sorted, so you start with pid
0 and work your way up.
Here is a Perl version to help you on your way (or to create complete
and utter confusion).
Gieben Expires July 11, 2015 [Page 99]
Internet-Draft Learning Go January 2015
#!/usr/bin/perl -l
my (%child, $pid, $parent);
my @ps=`ps -e -opid,ppid,comm`; # capture the output from `ps`
foreach (@ps[1..$#ps]) { # discard the header line
($pid, $parent, undef) = split; # split the line, discard 'comm'
push @{$child{$parent}}, $pid; # save the child PIDs on a list
}
# Walk through the sorted PPIDs
foreach (sort { $a <=> $b } keys %child) {
print "Pid ", $_, " has ", @{$child{$_}}+0, " child",
@{$child{$_}} == 1 ? ": " : "ren: ", "[@{$child{$_}}]";
}
9.6.11. Answer
There is lots of stuff to do here. We can divide our program up in
the following sections:
o Starting \verb|ps| and capturing the output.
o Parsing the output and saving the child PIDs for each PPID.
o Sorting the PPID list.
o Printing the sorted list to the screen.
In the solution presented below, we've used a "map[int][]int", i.e. a
map indexed with integers, pointing to a slice of ints -- which holds
the PIDs. The builtin "append" is used to grow the integer slice.
A possible program is:
Gieben Expires July 11, 2015 [Page 100]
Internet-Draft Learning Go January 2015
package main
import (
"fmt"
"os/exec"
"sort"
"strconv"
"strings"
)
func main() {
ps := exec.Command("ps", "-e", "-opid,ppid,comm")
output, _ := ps.Output()
child := make(map[int][]int)
for i, s := range strings.Split(string(output), "\n") {
if i == 0 { // kill first line
continue
}
if len(s) == 0 { // kill last line
continue
}
f := strings.Fields(s)
fpp, _ := strconv.Atoi(f[1]) // parent's pid
fp, _ := strconv.Atoi(f[0]) // child's pid
child[fpp] = append(child[fpp], fp)
}
schild := make([]int, len(child))
i := 0
for k, _ := range child {
schild[i] = k
i++
}
sort.Ints(schild)
for _, ppid := range schild {
fmt.Printf("Pid %d has %d child", ppid, len(child[ppid]))
if len(child[ppid]) == 1 {
fmt.Printf(": %v\n", child[ppid])
continue
}
fmt.Printf("ren: %v\n", child[ppid])
}
}
9.6.12. Number cruncher
o Pick six (6) random numbers from this list: 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 25, 50, 75, 100 Numbers may be picked multiple times.
Gieben Expires July 11, 2015 [Page 101]
Internet-Draft Learning Go January 2015
o Pick one (1) random number (i) in the range: 1 \ldots 1000.
o Tell how, by combining the first 6 numbers (or a subset thereof)
with the operators "+,-,*" and "/", you can make i.
An example. We have picked the numbers: 1, 6, 7, 8, 8 and 75. And i
is
1. This can be done in many different ways, one way is: ((((1 * 6) *
8) + 75) * 8) - 7 = 977 or (8*(75+(8*6)))-(7/1) = 977
Implement a number cruncher that works like that. Make it print the
solution in a similar format (i.e. output should be infix with
parenthesis) as used above.
Calculate _all_ possible solutions and show them (or only show how
many there are). In the example above there are 544 ways to do it.
9.6.13. Answer
The following is one possibility. It uses recursion and backtracking
to get an answer. When starting "permrec" we give 977 as the first
argument:
% ./permrec 977
1+(((6+7)*75)+(8/8)) = 977 #1
... ...
((75+(8*6))*8)-7 = 977 #542
(((75+(8*6))*8)-7)*1 = 977 #543
(((75+(8*6))*8)-7)/1 = 977 #544
package main
import (
"flag"
"fmt"
"strconv"
)
const (
_ = 1000 * iota
ADD
SUB
MUL
DIV
MAXPOS = 11
)
Gieben Expires July 11, 2015 [Page 102]
Internet-Draft Learning Go January 2015
var mop = map[int]string{ADD: "+", SUB: "-", MUL: "*", DIV: "/"}
var (
ok bool
value int
)
type Stack struct {
i int
data [MAXPOS]int
}
func (s *Stack) Reset() { s.i = 0 }
func (s *Stack) Len() int { return s.i }
func (s *Stack) Push(k int) { s.data[s.i] = k; s.i++ }
func (s *Stack) Pop() int { s.i--; return s.data[s.i] }
var found int
var stack = new(Stack)
func main() {
flag.Parse()
list := []int{1, 6, 7, 8, 8, 75, ADD, SUB, MUL, DIV}
magic, ok := strconv.Atoi(flag.Arg(0)) // Arg0 is i
if ok != nil {
return
}
f := make([]int, MAXPOS)
solve(f, list, 0, magic)
}
func solve(form, numberop []int, index, magic int) {
var tmp int
for i, v := range numberop {
if v == 0 {
goto NEXT
}
if v < ADD { // it's a number, save it
tmp = numberop[i]
numberop[i] = 0
}
form[index] = v
value, ok = rpncalc(form[0 : index+1])
if ok && value == magic {
if v < ADD {
numberop[i] = tmp // reset and go on
}
found++
Gieben Expires July 11, 2015 [Page 103]
Internet-Draft Learning Go January 2015
fmt.Printf("%s = %d #%d\n", rpnstr(form[0:index+1]), value, found)
}
if index == MAXPOS-1 {
if v < ADD {
numberop[i] = tmp // reset and go on
}
goto NEXT
}
solve(form, numberop, index+1, magic)
if v < ADD {
numberop[i] = tmp // reset and go on
}
NEXT:
}
}
func rpnstr(r []int) (ret string) { // Convert rpn to infix notation
s := make([]string, 0) // Still memory intensive
for k, t := range r {
switch t {
case ADD, SUB, MUL, DIV:
a, s := s[len(s)-1], s[:len(s)-1]
b, s := s[len(s)-1], s[:len(s)-1]
if k == len(r)-1 {
s = append(s, b+mop[t]+a)
} else {
s = append(s, "("+b+mop[t]+a+")")
}
default:
s = append(s, strconv.Itoa(t))
}
}
for _, v := range s {
ret += v
}
return
}
func rpncalc(r []int) (int, bool) {
stack.Reset()
for _, t := range r {
switch t {
case ADD, SUB, MUL, DIV:
if stack.Len() < 2 {
return 0, false
}
a := stack.Pop()
Gieben Expires July 11, 2015 [Page 104]
Internet-Draft Learning Go January 2015
b := stack.Pop()
if t == ADD {
stack.Push(b + a)
}
if t == SUB {
// disallow negative subresults
if b-a < 0 {
return 0, false
}
stack.Push(b - a)
}
if t == MUL {
stack.Push(b * a)
}
if t == DIV {
if a == 0 {
return 0, false
}
// disallow fractions
if b%a != 0 {
return 0, false
}
stack.Push(b / a)
}
default:
stack.Push(t)
}
}
if stack.Len() == 1 { // there is only one!
return stack.Pop(), true
}
return 0, false
}
10. References
10.1. Informative References
[bubblesort]
Wikipedia, , "Bubble sort", 2010.
[csp] Hoare, C., "Communicating sequential processes (csp)",
1985.
[duck_typing]
Wikipedia, , "Duck typing", 2010.
Gieben Expires July 11, 2015 [Page 105]
Internet-Draft Learning Go January 2015
[effective_go]
Authors, G., "Effective Go", 2010.
[fizzbuzz_cite]
Tech, I., "Using fizzbuzz to find developers...", 2010.
[go_blog_panic]
Authors, G., "Defer, panic, and recover", 2010.
[go_course_day3]
Pike, R., "The Go programming language, day 3", 2010.
[go_interfaces]
Taylor, I., "Go interfaces", 2010.
[go_nuts_interfaces]
Community, G., "Function accepting a slice of interface
types", 2010.
[go_spec] Authors, G., "Go language specification", 2010.
[go_tutorial]
Authors, G., "Go tutorial", 2010.
[go_web] Authors, G., "Go website", 2010.
[iota] Wikipedia, , "Iota", 2010.
[RFC1196] Zimmerman, D., "The finger user information protocol",
1990.
[RFC4627] Crockford, D., "The application/json media type for
javascript object notation (json)", 2006.
10.2. URIs
[1] fig/array-vs-slice.png
[2] fig/stack.png
[3] fig/reflection.png
[4] https://www.debian.org
Gieben Expires July 11, 2015 [Page 106]
Internet-Draft Learning Go January 2015
Index
A
array
multidimensional 20
B
built-in
append 19, 22
cap 19
close 19
complex 19
copy 19, 23
delete 19
imag 19
len 19
make 19, 54
new 19, 54
panic 19
print 19
println 19
real 19
recover 19
C
channel
blocking read 85
blocking write 85
non-blocking read 85
non-blocking write 85
unbuffered 85
channels 6, 83
complex numbers 19
D
duck
typing 72
F
field
anonymous 58
functions
as values 30
exported 44
literal 32
literals 30
method 28
named return parameters 28
Gieben Expires July 11, 2015 [Page 107]
Internet-Draft Learning Go January 2015
pass-by-value 28
private 44
public 44
receiver 28
signature 31
variadic 33
G
generic 75
goroutine 6, 82
I
interface 71
set of methods 71
type 71
value 71
io
buffered 89
io.Reader 90
K
keywords
break 16
continue 17
default 18
defer 31
defer list 32
else 15
fallthrough 18
for 16
go 82
goto 15
if 15
import 45
iota 11
map 23
map adding elements 24
map existence 24
map remove elements 24
package 43
range 17, 23
return 15
select 84
struct 57
switch 18
type 57
L
Gieben Expires July 11, 2015 [Page 108]
Internet-Draft Learning Go January 2015
label 15
literal
composite 20, 56
M
methods
inherited 59
N
networking
Dial 92
nil 54
O
operators
address-of 54
and 13
bit wise xor 13
bitwise and 13
bitwise clear 13
bitwise or 13
channel 83
increment 54
not 13
or 13
P
package
bufio 45, 49, 89
builtin 19
bytes 45
encoding/json 50
flag 50, 91
fmt 19, 49
html/template 50
io 49, 90
net/http 50
os 50
os/exec 50, 92
reflect 50, 78
ring 46
sort 49
strconv 49
sync 50
unsafe 50
R
reference types 20
Gieben Expires July 11, 2015 [Page 109]
Internet-Draft Learning Go January 2015
S
scope
local 29
slice
capacity 21
length 21
structures
embed 59
T
tooling
go 9
go build 9
go run 9
go test 47
type assertion 73
V
variables
assigning 9
declaring 9
parallel assignment 10
underscore 10
Author's Address
R. (Miek) Gieben
Email: miek@miek.nl
Gieben Expires July 11, 2015 [Page 110]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment