##Summary
Go is an open source programming language that focuses on concurrency (i.e. instead of sequentially/one after another).
###Why Go?
There’s sequential computing, which runs one command first, then another command as soon as the first is completed. Concurrent computing is different in that it has many computations executing during overlapping time periods. Concurrent computing is commonly confused with Parallel computing, but it doesn’t mean the same thing.
##Install
brew install go
.sudo apt-get install golang-go
##Go Tools
Go comes with a bunch of tools for managing Go code. You can access by typing in go
.
Some of these tools can you help build
(compile code), install
packages and dependences and run programs.
###Go Get
You can get source code by using go get
. For example, using go get golang.org/x/tour/gotour
.
###Go Install
You compile and install packages and dependencies using go install
.
So now you have some code, it should look something like this format:
bin/
hello # an executable file (e.g. $hello) runs the file
pkg/
darwin_amd64/
github.com/
williamqliu/
go-examples # a package that we made
string
string.a # package object
golang.org # a package that we got using go get
x/
net/
tools/
tour/... # goes down further to more package objects
src/
github.com/
williamqliu/
go-examples/
hello/
hello.go # our source code
hello_test.go # test code (must have _test in name)
golang.org
...
###Packages
Every Go program is made up of packages.
Packages start running in package main
.
A sample progam looks like:
package main
import(
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
You need the package name as main
and the func as main
.
You can have additional functions (e.g. say add), but you also have to define main
.
A name is exported if it begins with a capital letter.
E.g. if you write a function Pi
in the math
package, you can access this as math.Pi
.
###Sample Code
Okay let’s see some sample code already.
package main
import (
"fmt"
"math/rand"
"time"
)
var c, python, java bool // the 'type' (e.g. bool) goes after the variable name
var d, e int = 1, 2 // you can initialize variables
const Pi = 3.14 // you can make a constant with =. constants cannot be used with := syntax
func add(x, y int) int { // same as: x int, y int
return x + y
}
func swap(x, y string) (string, string) {
return y, x
}
func split(sum int) (x, y int) { // pass in a named variable 'sum'
x = sum * 4 / 9
y = sum - x
return // a 'naked' return (i.e. no arguments) returns the named values
}
func main() {
fmt.Printf("Hello, world\n") // Default format with Printf
fmt.Println("My favorite number is", rand.Intn(10)) // Print line
k := 3 // := is used in place of a 'var' declaration, creates with an implicit type
for i:=0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
fmt.Println("These two numbers added together are:", add(42, 13)) // using the 'add' function we made
a, b := swap("First", "Second") // using the 'swap' function we made
fmt.Println(a, b)
fmt.Println(split(17)) // using the 'split' function we made
var i int
fmt.Println(i, c, python, java) // by default, things are 0 or false (depending on type)
var c, python, java = true, false, "No!" // you can initialize variables
fmt.Println(d, e, c, python, java)
k := 3 // a short variable declaration means let Go figure out the type
fmt.Println(k)
w := 42 // same as: var w int = 42
x := float64(w) // doing a type conversion from int to float64, same as: var f float64 = float64(i)
y := uint(x) // a uint is a 'byte', same as: var u uint = uint(f)
z := rune(y) // a rune is an `int32`, mainly for Unicode code point
fmt.Println(z) // If you declare a variable, you have to use it or else it's an error!
fmt.Println("Pi is", Pi)
fmt.Println("The time is", time.Now())
}
You can then run the program with:
go build
go run hello.go
Similar to other for loops with an init, a condition expression (evaluated
before every iteration), and a post statement (evaluated at end of every
iteration). Notice there are no parenthesis surrounding the components of
these for loops. The init
and post
statements are optional (this means
that while
is for
in Go)
sum := 0
for i :=0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
// no need to setup init and post sections
sum :=1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
// for-loop is the while loop
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
// if you omit everything, an infinite loop is created
for {
}
Just like for-loops, you do not need parenthesis ()
around an if statement,
but {}
are required.
if x < 0 {
fmt.Println("Hey")
}
// You can do a short statement to execute before the condition that is
// only in scope until the end of the if statement
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
return lim
}
fmt.Println(pow(3, 2, 10))
Switch statements are pretty normal, parsing from top to bottom. If no
condition is given, then same as switch true
, which helps save long
if-else statements.
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X")
case "linux":
fmt.Println("Linux")
default:
fmt.Printf("%s", os)
}
// switch without a condition
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
A defer statement defers the execution of a function until the surrounding function returns. Deferred call’s arguments are evaluated immediately, but the function call is not executed until the surrounding funtion returns.
defer fmt.Println("world")
fmt.Println("hello")
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
Go uses pointers, which hold the memory address of a value.
*T
is a pointer to a T
value. Its zero value is nil
.&
operator generates a pointer to its operand.*
operator denotes the pointer’s underlying value.Some code examples:
var p *int // * means the pointer
i := 42
p = &i // p points to i
fmt.Println(*p) // read i through the pointer p
*p = 21 // set i through pointer p, aka 'dereferencing' or 'indirecting'
A struct is a collection of fields. You can access struct fields using a dot. Make sure to make variables capitalized so that data is exported outside of the struct (if lowercase, will not export)
type Vertex struct {
X int
Y int
}
type main(){
v := Vertex{1, 2}
fmt.Println(v)
// access struct fields using a dot
v.X = 4
fmt.Println(v.X)
// access struct fields through a pointer
p := &v
p.X = 1e9 // can also write as (*p).X, but usually no need for explicit dereference
fmt.Println(v)
}
A struct literal is a newly allocated struct value by listing the values of its
fields. You can list just a subset of the fields using the Name:
syntax.
&
is a special prefix that returns a pointer to the struct value.
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex, p is a pointer to a struct allocated on the heap
)
An array type [n]T
is an array of n
values of type T
.
e.g. var a [10]int
means a variable a
as an array of ten integers
An array’s length is part of its type, so arrays cannot be resized.
var a[2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
// initialize with values
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
A slice of an array describes the section of an underlying array, it does not store any data. Any changes to the slices will change the underlying array.
// slice
var s[]int = primes[1:4]
fmt.Println(s)
An array slice literal is like an array literal without the length.
// array literal
[3]bool{true, true, false}
// creates same array as above, then builds a slice that references it
[]bool{true, true, false}
When slicing, you can omit the high or low bounds to get the defaults. Default is zero for the low bound and the length of the slice for the high bound.
var a [10]int
a[0:10]
a[:10]
a[0:]
a[:]
A slice has both a length and a capacity.
nil
. A nil slice has a length and capacity of
0 and no underlying array.Use len(s)
and cap(s)
to get length and capacity of a slice.
s :=[]int{2, 3, 5, 7, 11, 13}
// slice the slice to give it zero length
s = s[:0]
// extend a slice's length
s = s[:4]
// drop its first two values
s = s[2:]
var anothers []int
if anothers == nil{
fmt.Println("nil")
}
make
You can use the built-in make
function to create dynamically-sized arrays.
The make function allocates a zeroed array and returns a slice that refers to
that array.
a := make([]int, 5) // len(a)=5
// to specify a capacity, pass a third argument to make
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
Slices can contain any type, including other slices.
// Create a tic-tac-toe board
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// players take turns
board[0][0] = "X"
board[2][2] = "O"
board[1][2] = "X"
board[1][0] = "O"
You can use a built-in append
to append new elements to a slice.
func append(s []T, vs ...T) []T
What this means is to append to slice s of type T with T values to append. In return you get all the elements of the original slice plus the provided values. If the array s is too small to fit, then a bigger array is allocated.
var s []int
s = append(s, 0) // append works on nil slices
s = append(s, 1) // slice grows as needed
s = append(s, 2, 3, 4) // can add more than one element at a time
You can use range
to iterative over a slice or map.
_
Code example:
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
for _, value := range pow {
fmt.Printf("%d", value)
}
A map maps keys to values.
The zero value of a map is nil
. A nil map has no keys, nor can keys be added.
The make
function returns a map of the given type, initialized and ready to
use.
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68, -74.39,
}
fmt.Println(m["Bell Labs"])
}
Map literals are like struct literals, except the keys are required.
// Map Literals
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68, -74.39,
},
"Google": Vertex{
37.42, -122.98,
},
}
// If the top-level type is just a type name, you can omit it from the
// elements of the literal. For example, this is the same as above:
var m = map[string]Vertex{
"Bell Labs": {40.68, -74.39},
"Google": {37.42, -122.08},
}
You can modify maps with the following actions (assuming a map m):
elem = m[key]
m[key] = elem
delete(m, key)
You can also check that an element is present with a two-value assignment
elem, ok = m[key]
// if 'key' is in 'm', then 'ok' is 'true', else 'ok' is 'false'
// if 'key' is not in 'm', then 'elem' is the zero value for the maps'
// element type
// if 'elem' or 'ok' have not yet been declared, use this short hand:
elem, ok := m[key]
Functions are values too, meaning they can be passed around like other values.
Go does not have classes. You can define methods on types.
func
keyword and
the method nameCode example where the Abs
method has a receiver v
of type Vertex
and
returns a float64.
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// can also be written as a regular function with no change in functionality
func Abs(v Vertex) float64{
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
You can declare a method on non-struct types.
E.g. numeric type MyFloat
with an Abs
method.
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
}
You can declare methods with pointer receivers.
The receiver type has the literal syntax *T
for some type T
Methods with pointer receivers can modify the value to which the receiver
points. Pointer receivers are more common than value receivers.
An interface type is defined as a set of method signatures. A value of interface type can hold any value that implements those methods.
type Abser interface {
Abs() float64
}
type MyFloat float64
type Vertex struct {
X, Y float64
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat implements Abser
a = &v // a *Vertex implements Abser
}
Below are good tools to use:
gofmt
errcheck
go build
GOOS=windows go build
allows cross compilation (e.g. windows creates
.exe)go list -f ':
to list package names and documentationgo doc
to get documentation from a package (e.g. go doc fmt
, go doc fmt
Printf
, godoc -http :6060
to run documentation server)go get github.com/golang/example/hello
Make a file with a name ending in _test
so that the test runner can pick up,
e.g. main_test.go
package main
import "testing"
func TestHandler(t *testing.T) {
t.Errorf("Something went really wrong")
}
There are also benchmarking options.
Use go-wrk
to run load testing. Install from:
go get github.com/adjust/go-wrk
You’ll see:
You can see what your code is doing by instrumenting your code.
import (
"net/http"
_ "net/http/pprof"
)
Then visit localhost:8080/debug/pprof/
and you can list the heap, the
coroutines, number of times garbage collection ran, how long were pauses.
Use go’s tool pprof to measure the performance of your binary
E.g. `go tool pprof --seconds=5 localhost:8080/`
Uber’s go tool to measure the performance of your binary and creates an easier to read “Flame Graph”.
go get github.com/uber/go-torch
Meetup hosted by bitly
:user
)
go/src/github.com/...
r := chi.NewRouter()
r.Get("/users/:user/repos", getUser)
r.Use(middleware.Logger)
Package manager is govendor
, will look at /vendor/
first.
* govendor init
* govendor fetch github.com/pressly/chi@v2.1
* will appear as /vendor
in your github (e.g.
go/src/github.com/williamqliu/go-app/vendor/
* imports in as github.com/pressly/chi
Check for package to handle errors nicer so less repeated code
Reflex is language agnostic, pass in shell and does hot reloading
Middleware:
Useful middleware includes:
Structs
Structs represents cursor
type GithubRepo struct {
FullName string `json:"full_name"`
}
HTTP
Do not use straight http.Get("someurl")
- default client used to not have
timeout by default? Can check by looking at http.Client
Kyle’s live coding without seeing his cursor!
Neat, built-in json parsing into standard library
func getRepos(w http.ResponseWriter, r *http.Request) {
user := chi.URLParam(r, "user")
urlStr := fmt.Sprintf("https//api.github.com/users/%s/repos", user)
resp, err := http.Get(urlStr)
if err != nil {
log.Printf("%+v", err)
http.Error(w, http.StatusText(500), 500)
return
}
var repos []*GithubRepo
json.NewDecoder(resp.Body).Decode(&repos)
b, err := json.Marshall(repos)
if err != nil {
log.Printf("%+v", err)
http.Error(w, http.StatusText(500), 500)
return
}
w.Header().set("Content-Type", "application/json")
}
Another code example
func (h Handler) Routes() chi.Router {
}
...
at ar.Mount("/repos", reposHandler.Routes())
Documentation
godoc Step through: delve
Code organization:
repos with handlers as packages organize by resource as a package (e.g. models) organize by service as a package
Additional things to look up:
Package SQL provides what you need, no need to have an ORM gorm is an ORM sqlx gives you a little bit of sugar and not a full blown ORM a library writes to a file, then you write the implementation of the database; boltdb
Jason Keene from Pivotal
A tour of gRPC in Go
What is gRPC?
How to use it
sigint and sigterm to handle interrupt signal
How to protect API from unauthorized access?
How do I roll out new versions of my API?
What happens if things go wrong?
How does it compare to others?
REST/JSON Pro: Everywhere Con: No streaming - can add on streaming with websockets though Con: Text based encoding Con: Text based transport (lots of repeated bytes over the wire)
Websockets Pro: Bi-directional streaming Pro: Large adoption with proxies and firewalls Con: Can not interleave data frames Con: Seems to be obsolted by http2
gRPC Pro: All in Golang, goes well with Go ecosystem
TypeOf
)http
) for easier alternative to curl
. ==
is query param,
=
is json bodyResources
Concourse Talk
https://github.com/jasonkeene/concourse-demo
Summary:
fly -t local-demo set-pipeline -c pipeline/example.yml -p
example
fly -t local-demo hijack -j
example/run-tests
Get IP Address of Docker Compose
export CONCOURSE_EXTERNAL_URL=”http://$(ifconfig en0 inet | grep inet | awk ‘{print $2}’):8080” |
#####Sample Job - pipeline/main.yml
Code
jobs:
- name: hello
plan:
- task: hello
config:
platform: linux
image_resource: # defines docker image
type: docker-image
source:
repository: golang
run:
path: /bin/bash
args:
- -c
- echo 'hello gophers'
task.yml file
platform: linux
finds a linux workerimage_resource: type: docker-image...
create a resourceinputs: - name: my-app
mountsScheduling is hard
Mounting volume types to a container is a pain. Its a reference to the volume.