This document provides an overview of Golang basics for Java developers. It covers Golang's history, features, syntax, data types, flow control, functions and interfaces, concurrency, and differences from Java. Key points include Golang being a compiled, statically typed language created at Google in 2007, its use of packages and imports, basic types like strings and integers, slices for dynamic arrays, maps for key-value pairs, functions with receivers, errors instead of exceptions, and goroutines for concurrency with channels.
4. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
5. History and features
Created in 2007 at Google, announced in 2009, v1.0 released in 2012) with strong
dedication for server side programming.
Compiled, statically typed, garbage collected language with multiple
architecture/OS support (i386, amd64, arm/Windows, Linux, *BSD, etc..)
(very) fast compilation AND execution time with low resource consumption
Powerful cli (go get, go build, go test, go install…)
Current stable version is 1.6.3 and still being actively developed
6. What is missing or disturbing?
No generics
Not an OO language
No constructors
No operator/method overloading
No circular package imports
No mandatory semicolons
GC pause is unpredictable
7. What is non-java-isch?
Multiple return values + the blank variable
Golang is a pass-by-value language
Lightweight concurrency with goroutines and channels
No SE/EE separation. All server stuff is built-in.
No exceptions, use error instead
Compile time error about unused imports and variables
No maven/ant like build system. Uses Makefile+vendoring+go get
8. Famous projects, companies
Projects:
App Engine with Go, AWS with Go SDK, Docker, Kubernetes, Grafana, Terraform,
Gogs (Go Git Service), etcd, drone.io, Syncthing, CockroachDB, rkt, nsq, consul,
boltDB, weave, swarm, vulcand, gryffin, fleet, minio…
Companies:
Google (of course…), Netflix, Dropbox, CloudFlare, SoundCloud, BBC, Uber,
Couchbase, MongoDB...
11. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
12. Hello world in golang:
package main
// imports
import "fmt"
/*
This is the main function
*/
func main() {
fmt.Println("Hello, World!")
}
Try it in the Go playground!
Hello world
13. Go project structure
❏ Workspace ($GOPATH or %GOPATH%)
❏ src/pkg/bin roots
❏ Repository (github.com, etc…)
❏ Package
❏ Go source files
15. Packages
Like in Java, golang also uses packages to organize code, but in a bit different
format.
Keyword: package <name>
The app starts in the main package.
the path to the package’s directory is the import path
The package name is the last element of the import path:
github.com/zooplus/golang-app/stringutil → stringutil
Accessing stringutil functions/elements: stringutil.<name>
17. Package types
To use one or more functions in a package we need to import it into our code. We
can import system, local and remote packages.
System packages are the golang out of box packages like http, testing, etc..
Local package resides in your repository, no full path needed
Remote packages has complete import path pointing to the server like:
github.com/emicklei/go-restful
18. Getting the dependencies
For remote packages use go get to fetch into your workspace. We have two
syntaxes
go get in the repository folder downloads all remote packages based on the
imports
go get <remote path> downloads the specified package for later use
19. Variables, constants
package main
import "fmt"
const greeting = "Hello"
var name string
func main() {
name = "Zooplus"
space := " "
fmt.Println(greeting + space + name)
}
20. if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Printf("%s does not existn", path)
}
The blank identifier
“The blank identifier can be assigned or declared with any value of any type, with the value
discarded harmlessly”
(https://golang.org/doc/effective_go.html#blank)
21. Exported names
“In Go, a name is exported if it begins with a capital letter.
For example, Pizza is an exported name, as is Pi, which is exported from the math package.”
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi)
}
22. Practice!
Refactor the greeting app to use fmt.Printf(format, args...)** and display the following message:
Hello Zooplus, today is Friday.
The name of the day as string can be printed with:
import "time"
...
time.Now().Format("Monday")
**(Use %s for string)
23. A solution
package main
import (
"fmt"
"time"
)
func main() {
name := "Zooplus"
fmt.Printf("Hello %s, today is %s.", name, time.Now().Format("Monday"))
}
24. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
25. Basic types
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32, represents a Unicode code point
float32 float64
complex64 complex128 - “math/cmplx”:
var number complex128 = cmplx.Sqrt(-5 + 12i)
26. Pointers - bit.ly/2a58jnI
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // point to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
}
27. package main
var (
a int
b int32
c int16
)
func main() {
a = 1
b = a
c = a
}
No autoboxing! You should convert your types by yourself.
package main
import "fmt"
var (
a int
b int32
c int16
)
func main() {
a = 1
b = int32(a)
c = int16(a)
fmt.Printf("a: %d, b: %d, c: %d", a, b, c)
}
Type conversion
prog.go:11: cannot use a (type int) as type int32 in assignment
prog.go:12: cannot use a (type int) as type int16 in assignmenta: 1, b: 1, c: 1
28. Struct
type ApacheLogRecord struct {
ip
string
time
string
method, uri, protocol
string
status int
responseBytes int
referer
string
userAgent
string
}
1. result = &ApacheLogRecord{
ip: nvl(req.RemoteAddr),
time: timeFormatted,
method: nvl(req.Method),
uri: nvl(req.URL.Path),
protocol: nvl(req.Proto),
status: resp.StatusCode(),
responseBytes:
resp.ContentLength(),
referer: nvl(req.Referer()),
userAgent:
nvl(req.UserAgent()),
}
2.) result = new(ApacheLogRecord)
29. package main
import "fmt"
type Animal struct {
legCount int
}
// define a behavior for Animal
func (a Animal) numberOfLegs() int {
return a.legCount
}
type Dog struct {
Animal //anonymous field Animal
}
func main() {
d := Dog{Animal{4}}
//no method defined for Dog, but we have the same behavior as Animal.
fmt.Println("A Dog has this many legs: ", d.numberOfLegs())
}
Embedding, inheritance -bit.ly/2axY1yu
30. Receiver methods -bit.ly/2a56VkS
package main
import "fmt"
type Animal struct {
legCount int
}
func (a Animal) numberOfLegs() int {
return a.legCount
}
func (a Animal) setLegs(c int) {
a.legCount = c
}
type Mammal struct {
weight int
}
func (m Mammal) getWeight() int {
return m.weight
}
func (m Mammal) setWeight(w int) {
m.weight = w
}
type Dog struct {
Animal
Mammal
}
func main() {
d := Dog{Animal{4}, Mammal{10}}
fmt.Printf("A Dog has this many legs: %d oh... and weight: %d", d.numberOfLegs(), d.getWeight())
}
31. Pointer receivers -bit.ly/2aKK7si
package main
import "fmt"
type Animal struct {
legCount int
}
func (a Animal) numberOfLegs() int {
return a.legCount
}
func (a Animal) setLegs(c int) {
a.legCount = c
}
func (a *Animal) setLegsPtr(c int) {
a.legCount = c
}
type Dog struct {
Animal //anonymous field Animal
}
func main() {
d := Dog{Animal{4}}
fmt.Println("A Dog has this many legs: ", d.numberOfLegs())
d.setLegs(5)
fmt.Println("A Dog has this many legs: ", d.numberOfLegs())
d.setLegsPtr(6)
fmt.Println("A Dog has this many legs: ", d.numberOfLegs())
}
32. Arrays -bit.ly/2ahx5EA
Arrays has fix size and type with zero based indexing:
var integers [20]int
package main
import "fmt"
func main() {
var a [2]string // std declaration
a[0] = "Hello"
a[1] = "Zooplus"
fmt.Println(a[0], a[1])
fmt.Println(a)
fibonacci := [6]int{1, 1, 2, 3, 5, 7} // on-the-fly declaration
fmt.Println(fibonacci)
}
33. Slices - bit.ly/2ahVarP
Slice is a dynamic version of array (a sort of):
var integers []int // decleration of a slice without size
package main
import "fmt"
func main() {
fibonacci := [6]int{1, 1, 2, 3, 5, 7}
var p []int = fibonacci[1:4]
fmt.Println(p)
}
34. Slices are not storing data - bit.ly/2aai1Wx
package main
import "fmt"
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names)
a := names[0:2]
b := names[1:3]
fmt.Println(a, b)
b[0] = "XXX"
fmt.Println(a, b)
fmt.Println(names)
}
35. Slices - bounds
There are default low and high bounds for slices. Given the following array:
var a [10]int
The following slice declarations are equivalent:
a[0:10]
a[:10]
a[0:]
a[:]
36. Creating slice:
a := make([]int, 5) // len(a)=5
Creating slice with capacity:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
Appending slice:
b = append(b, 10)
Further reading: https://blog.golang.org/go-slices-usage-and-internals
Slices - create, append
37. Arrays, slices - for loop as foreach
Iterate through an array/slice
for index, value := range arr {
fmt.Println("Index:", index, "Value:", value)
}
Get the index only:
for index := range arr {
fmt.Println("Index:", index)
}
Get the values:
for _, value := range arr {
fmt.Println("Value:", value)
}
38. Maps - declaration, initialization
Maps are not initialized by default, we should use make:
package main
import "fmt"
var m map[string]string
func main() {
m = make(map[string]string)
m["Zooplus"] = "Gut"
m["Bitiba"] = "Gut"
m["Fressnapf"] = "Falsch"
fmt.Println(m["Zooplus"])
}
39. Maps - Mutating maps
m[key] = item // upsert
item = m[key] // retrieve
delete (m, key) // guess….
_, ok = m[key] // ok == true if key exists, map can store/return nil
Maps are not thread safe!!!
40. Maps - for loop as foreach
Iterate through a map:
for key, value := range m {
fmt.Println("Key:", key, "Value:", value)
}
Get the keys:
for key := range m {
fmt.Println("Key:", key)
}
Get the values:
for _, value := range m {
fmt.Println("Value:", value)
}
41. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
42. The one and only: for loop
// normal loop
sum := 0
// init-condition-post
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
// partial loop
sum := 0
// init and post are optional
for ; sum < 10; {
sum += sum
}
// “while” loop
sum := 1
// init and post are optional
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
// infinite loop
for {
}
43. func GetProject(req *restful.Request, resp *restful.Response) {
resp.Header().Set("Pragma", "no-cache")
//
pId := req.PathParameter("projectId")
if project, ok := projects.GetProjectByIdOrName(pId); ok
{
ReturnJSON(resp, http.StatusOK, project)
}
ReturnMessage(resp, http.StatusNotFound, "Project not
found!")
}
If-then-else
existingPipeline, ok := nameSpace.Pipelines[newPipeline.Name]
if ok {
log.Debug("Entry exists!")
} else {
nameSpace.Pipelines[newPipeline.Name] = existingPipeline
log.Debug("New entry stored")
}
?
44. Switch
Switch in Golang is a bit different from Java:
No automatic fallthrough, no need to put break at the end in every cases
You can delegate expression evaluation into the case block
fallthrough keyword for java-ish behavior
Multiple conditions in one case (no empty cases like in java)
Not limited to string and int
Type switch can be used for interface{} to find out the real type (instanceof)
45. Switch - no fallthrough by default
switch c {
case '&':
esc = "&"
case ''':
esc = "'"
case '<':
esc = "<"
case '>':
esc = ">"
case '"':
esc = """
default:
panic("unrecognized escape character")
}
46. Switch - strings are welcome
switch syscall.OS {
case "windows":
...
case "plan9":
...
default:
...
}
47. Switch - (multiple)expression(s) in cases
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
switch chars[code].category {
case "de", "uk", "fr", "sp", "nl":
return true
}
48. Switch - Type switch
switch v.(type) {
case int:
return "int"
case string:
return "string"
default:
return "unknown"
}
49. Switch - you can break it
switch argv[0] {
case "echo":
fmt.Print(argv[1:]...)
case "cat":
if len(argv) <= 1 {
fmt.Println("Usage: cat <filename>")
break
}
PrintFile(argv[1])
default:
fmt.Println("Unknown command; try 'echo' or 'cat'")
}
50. Switch - fallthrough
switch len(src) {
default:
v |= uint32(src[3])
fallthrough
case 3:
v |= uint32(src[2]) << 8
fallthrough
case 2:
v |= uint32(src[1]) << 16
fallthrough
case 1:
v |= uint32(src[0]) << 24
}
51. Errors instead of exceptions
Golang has no exceptions
and of course there are no checked exceptions :)))))))
No try-catch-finally.
Error is just an interface
Functions are often returning a value and an error together.
Checking this error for nil is the exception handling in Golang:
// validate
pipeline, err := validateYaml(buf.Bytes())
if err != nil {
errorMessage := fmt.Sprintf("Error parsing pipeline config: %s", err)
log.Error(errorMessage)
http.Error(w, errorMessage, http.StatusBadRequest)
} else {...}
NO CHECKED EXCEPTIONS!!!
53. Panic and Recover -bit.ly/2a5m0mJ
func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
54. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
55. Functions -bit.ly/2a5mg4W
package main
import "fmt"
func swap(x, y string) (string, string) { // also can use (x string, y string)
return y, x
}
func main() {
a, b := swap("hello", "zooplus")
fmt.Println(a, b)
}
57. Interfaces
Golang has no “implements” keyword. If you implement all methods defined by the
interface, then you are implemented the interface implicitly.
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()
}
58. The empty interface - bit.ly/2awwq3Z
Like Object in Java, Golang has the interface{} as type that compatible with every
value (even with primitives).
So it can hold any value. You need type assertion to find out what is it:
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // panic
fmt.Println(f)
}
59. Reflection
“In computer science, reflection is the ability of a computer program to examine
and modify its own structure and behavior (specifically the values, meta-data,
properties and functions) at runtime.” /Wikipedia/
Golang has a reflection package to inspect structs, interfaces or methods runtime
like in Java and also you can change the values of the fields.
What you’ll miss is some bytecode manipulation and proxy generation. Mockito
like framework is not possible in Golang.
See more: http://blog.ralch.com/tutorial/golang-reflection/
60. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
62. Differences from Java
Goroutine is lightweight, but not reusable
No Threadlocal or Executorservice in Golang
Golang has no thread safe map implementation by default
(https://github.com/streamrail/concurrent-map)
Golang is a pass-by-value language
Golang uses channels to communicate between threads
Golang unsafe package is more limited
To summarize: Java originally built-on the shared memory concept, but the
Golang is focusing on the communication with channels
63. Channels
ch := make(chan int) // single item channel
v:= 5
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
ch := make(chan int,100) // buffered channel
v:= 5
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
64. Looping on a channel
package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
65. Overview
Basic syntax and structure
Datatypes
Flow control
Functions, interfaces
Concurrency
Java vs. Go
66. Go and Java common points
C like (braces)
Garbage collector
Memory safety (nil/null references, runtime bounds checks)
Statically typed
Variables initialized by default(zero/nil/false)
Methods, Interfaces
67. Go and Java differences
Native code without VM + statically linked binaries
Control over memory layout
Function values and lexical closures
Built-in strings (UTF-8)
Built-in generic maps and arrays/slices
Built-in concurrency
68. Go missing parts (by intention…)
No inheritance
No constructors
No classes
No implements
No final
No exceptions
72. Next steps
Go by example (https://gobyexample.com)
Tutorial (https://tour.golang.org/welcome/1)
Effective go (https://golang.org/doc/effective_go.html)
Awesome Go: https://go.libhunt.com/
A workspace is a directory hierarchy with three directories at its root:
src contains Go source files,
pkg contains package objects, and
bin contains executable commands.
The go tool builds source packages and installs the resulting binaries to the pkg and bin directories.
The src subdirectory typically contains multiple version control repositories (such as for Git or Mercurial) that track the development of one or more source packages.
The tree above shows a workspace containing two repositories (example and image). The example repository contains two commands (hello and outyet) and one library (stringutil). The image repository contains thebmp package and several others.
A typical workspace contains many source repositories containing many packages and commands. Most Go programmers keep all their Go source code and dependencies in a single workspace.
No static import in golang
ANIMATED! Import has two formats, the last import is a remote package! What does it mean? Let’s talk about the package types
So that’s all about the folders and dependencies, let’s start with the language elements
ANIMATED! We have a package and we imported all stuff we need, so let’s declare some variables. Variable scopes: global with capitalized name, package local withotu capital, local to func/block, and
short within if-s. Will be discussed there.
ANIMATED! Use blank variable to ignore a return value, but use it carefully! An example from the os package.
ANIMATED! Math.pi is not exported, invisible outside of the math package. Fix it to change pi to PI. then we are done with the basic syntax.
Let’s talk about the golang basic types.
ANIMATED! The building block of complex data structures. Int, uint and uintptr are 32/64 wide, depending on the system they run.
Go has pointers. A pointer holds the memory address of a variable. This is from the tour of go site.
bit.ly/2a58jnI
ANIMATED!
ANIMATED! Struct is a complex type which contains named fields
ANIMATED! There’s no classical inheritance in Golang, because we are using EMBEDDING. It makes multiple inheritance and composition possible. Let’s see the example.
Here we are inheriting the Dog’s method. But wait… What is this numberOfLegs stuff?
bit.ly/2axY1yu
This is a receiver method!
We can attach methods to structs and they can invoked via the struct instances like the object methods in Java.
No static methods for structs!
This methods can be inherited with embedding and we can embed multiple items so we can inherit from multiple sources.
THe a and m is representing the THIS in java.
These are the VALUE receivers. They’re receiving the struct by value and the content can’t be changed. What to do if we want to mutate the content? The answer in the next slide…
bit.ly/2a56VkS
With pointer receiver we can change the value of the struct.
bit.ly/2aKK7si
You can’t resize the array, so if you need dynamic solution, you need something else.. Next slide…
bit.ly/2ahx5EA
An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array. In practice, slices are much more common than arrays. Same structure existing in Python. So if you familiar with python, then the slice shouldn’t surprise you.
Slices are like references to arrays. A slice does not store any data, it just describes a section of an underlying array.
Changing the elements of a slice modifies the corresponding elements of its underlying array.
Other slices that share the same underlying array will see those changes.
bit.ly/2ahVarP
Slice is a pointer to the underlying array. If you change the array, the slice is also changing. Quite familiar right? This is a nice example of the lightweight design pattern.
bit.ly/2aai1Wx
When slicing, you may omit the high or low bounds to use their defaults instead.
The default is zero for the low bound and the length of the slice for the high bound.
We can use make to create a slice from scratch. This is the way to create dynamic sized arrays, but we can’t decrease the size. The slice topic is quite big, I recommend to read the linked article about slice internals… Next slide: foreach
A bit early to talk about for, but this is the right place for mentioning. Foreach for arrays and slices. First item is the index, second (optional) is the value. Next: maps
Maps are quite huge topic, so only few feature are covered here. They’re the same key-value stuff like in java, but the implementation details are hidden (arraymap, linkedlistmap,etc… who knows?)
Maps are quite huge topic, so only few feature are covered here. They’re the same key-value stuff like in java, but the implementation details are hidden (arraymap, linkedlistmap,etc… who knows?)
Maps has key and value and golang can handle them in a for loop.
ANIMATED! Golang has only one loop type: for. No while or do-while, nothing. Just the for. Golang for don’t need brackets. We can use for in multiple ways:
Normal, partial, while, infinite or range (as foreach discussed later)
ANIMATED! If like in java without braces, but we have an additional syntax: the short statement
THe variable declared in short statement lives only within the if.
With a type switch you can switch on the type of an interface value (only):
The 'fallthrough' must be the last thing in the case! Not recommended if other structure can replace it. Next: errors
ANIMATED!
In Java 8 finally we’ve got the try-with-resources statement, to clean up things, but only works with Closeable interface. IMHO it’s a bit tight coupled, but works. Golang has bigger freedom, because we can specify any statement to run. You can specify the resource releasing mechanism right there where the resource occupied. Not just open/close, but lock/unlock is possible. Print a header then footer at the end.
The defer evaluation order is Last In First Out so the println will run first.
Panic is a built-in function that stops the ordinary flow of control and begins panicking.When panic called, the function stops, executes the defers normally, then return to its caller and the panicking continues until the app stops or...
Recover is a built-in function that regains control of a panicking goroutine. Only usable as deferred function. In normal execution it returns a nil, otherwise the value given to the panic. The call recover() resumes the normal execution and stops panicking.
Panic/Recover behaves like the exception handling in java.
bit.ly/2a5m0mJ
A function can take zero or more arguments and can return zero or more arguments.
bit.ly/2a5mg4W
Also you can give name the return value and they acting like a declared variable. In this case you don’t need to specify them in the return.
bit.ly/2aymMe6
bit.ly/2awwq3Z
Concurrency is so big topic, we are just overviewing the golang specialities
Goroutines are lightweight, but you can’t reuse them when they’re finished. You can create hundreds of goroutines quickly, no need of reuse or caching like in java.
No executorservice or threadlocal
Maps are not thread safe
In golang the channels are used to share unit of work between threads, thread safe and you can define the capacity of the channel. Communicate over shared channels, and synchronized access is not necessary.
Thread pooling is tricky in golang.
Channel is a FIFO pipe with fix size. We can put and read items from a channel.
The direction of the arrow shows the dataflow.
This is a single item channel
Channels are blocked and waiting to the data for indefinite time
The common pattern for queue communication is the poison pill, to show to the receiver, no more data left and stop the operation.
In golang we can close the channel to release the blocked reader.
For-select skipped here, but used for timeouts
Clarity and readability is critical in golang.
The next session will be a workshop to develop an app