Go for SysAdmins - LISA 2015

112
November 8–13, 2015 | Washington, D.C. www.usenix.org/lisa15 #lisa15 Go for Sysadmins Chris "Mac" McEniry @macmceniry

Transcript of Go for SysAdmins - LISA 2015

Page 1: Go for SysAdmins - LISA 2015

November 8–13, 2015 | Washington, D.C.www.usenix.org/lisa15 #lisa15

Gofor

Sysadmins

Chris "Mac" McEniry@macmceniry

Page 2: Go for SysAdmins - LISA 2015

Intro

Page 3: Go for SysAdmins - LISA 2015

Goals• Gain a novice understanding of the Go Programming Language

• Know how to apply that understanding to common work tasks that Sysadmins see

Page 4: Go for SysAdmins - LISA 2015

Why Go?• Simple enough language to keep it in your head

• Built-in Concurrency Primitives

• Fast Compilation

• Simplified Deployments

• Flexibility of a dynamic language. Safety of a static language

• Built in garbage collection - avoid memory game

Page 5: Go for SysAdmins - LISA 2015

Why Go for Sysadmins?• Targeted for system programs

• Ease of distribution

• Ease of language

Page 6: Go for SysAdmins - LISA 2015

Why? Targeted for system programs• Small memory footprint

• Fast

• Similar patterns to unix tools

Page 7: Go for SysAdmins - LISA 2015

Why? Ease of Distribution• Compiled single binary

• Supports multiple platforms

• Linux

• MAC

• FreeBSD, OpenBSD, NetBSD, DragonFly BSD

• Windows

• Solaris

• Plan9

Page 8: Go for SysAdmins - LISA 2015

Why? Ease of Language• Simple Spec

• https://golang.org/ref/spec

• 45 pages printout

• Enforced conventions

• Opinionated

Page 9: Go for SysAdmins - LISA 2015

Opinionated• There’s a way to do whitespace: gofmt

• Very few control structures (8 statement terminating keywords)

• Just one loop: for

• No semicolons (mostly - only where it’s useful)

• No extra parenthesis in conditionals

• All errors, no warnings

• Must use what you declare

• Everything is initialized

• "Order not specified" really does mean you can’t rely on the return order

Page 10: Go for SysAdmins - LISA 2015

Who’s using Go?• CloudFlare

• Cloud Foundry

• CoreOS

• Digital Ocean

• GOV.UK

• Medium

• SoundCloud

• Twitch

• Twitter (Answers)

• https://github.com/golang/go/wiki/GoUsers

Page 11: Go for SysAdmins - LISA 2015

Projects using Go• Docker

• Camlistore

• Hugo

• juju

• Heka

• RethinkDB

• etcd

• https://code.google.com/p/go-wiki/wiki/Projects

Page 12: Go for SysAdmins - LISA 2015

How does this tutorial work?• Hands on work in a choose your own adventure style

• The material in this presentation is largely for reference

• The exercises are broken up by portions of common tasks which will come up in a sysadmin’s regular course (e.g. reading files, reading directories, performing regex, etc)

• Each exercise references presentation sections. Those presentation sections are the language items necessary to do the exercise. Presentation sections are labeled on the bottom right of each slide

• Some exercises have multiple approaches to show different ways and different language parts

Page 13: Go for SysAdmins - LISA 2015

Font Conventions• Informational text - Helvetica

• Code - Chalkboard

• Shell - Courier

var ( foo = 1 bar = 2)

echo "hello FOO" | sed -e 's/FOO/world/;'

Page 14: Go for SysAdmins - LISA 2015

Setup• Get a VM, if need be

• Most exercises have been worked on with CentOS6 and OS X. YMMV

• A Vagrantfile is provided in the Repo if it helps

• Get Code Repo

• git clone https://github.com/cmceniry/g4sa-tutorial

• Vagrant VM is up to date

• git pull on USB

Page 15: Go for SysAdmins - LISA 2015

Setup• Get Go, if need be

• https://golang.org/dl/

• Go 1.5.1

• Untar in /usr/local/go

• Add environment variables

• This is set already on Vagrant VM

export GOPATH=/usr/local/goexport PATH=${PATH}:${GOPATH}/bin

Page 16: Go for SysAdmins - LISA 2015

Setup• Set GOPATH

• Not using this much in this tutorial, but do need a place for pulled in libraries and build files

• Recommend ${CODEREPO}/workspace

• Can use /tmp/workspace or equivalent

• This is set already on Vagrant VM

Page 17: Go for SysAdmins - LISA 2015

Setup• Confirm it's all working

[vagrant@g4sa ~]$ cd g4sa-tutorial/[vagrant@g4sa tutorial]$ go run helloworld/helloworld.go Welcome to Go![vagrant@g4sa tutorial]$ go get github.com/kr/fs[vagrant@g4sa tutorial]$

Page 18: Go for SysAdmins - LISA 2015

Using the code repo• Code Repo is broken up in exercise directories

• Each exercise directory has:

• README.md

• Description about the exercise

• Presentation reference information

• Any setup steps or other caveats about the exercise

• Main exercise file - incomplete and will need to be filled out

• answer directory with a way to finish up the exercise file

Page 19: Go for SysAdmins - LISA 2015

Getting Started

Page 20: Go for SysAdmins - LISA 2015

Tools• Most interactions are through the go subcommands

• go run : Compile and run go code

• go build : Build a standalone object file or executable

• go test : Run test suite

• go install : Install from the source tree a package or binary

• go doc / godoc : Extract/Generate/Show documentation

• go fmt / gofmt : Applies standard formatting to go source files

• go get : Download module src from an upstream repository

• go help : Command line help

gettingstarted

Page 21: Go for SysAdmins - LISA 2015

Go Workspace• Standard way of structuring projects

• bin : Binary locations

• pkg : Compiled libraries

• src : Source locations - project and dependency libraries

• Subdirectories represent package paths

• Workspace is not what goes under version control

• Actually is some subdirectory inside of src directory

• Set GOPATH to match Workspace directory

gettingstarted

Page 22: Go for SysAdmins - LISA 2015

Tools• go run allows you to treat it like a scripting language

• Edit and run in a quick iteration

• Avoid much of the workspace setup

• Though if there are dependencies, you still need a place to put them

• We’re going to stick with go run for this tutorial

gettingstarted

Page 23: Go for SysAdmins - LISA 2015

Hello World - running[vagrant@g4sa helloworld]$ go run helloworld.goWelcome to Go![vagrant@g4sa helloworld]$

gettingstarted

Page 24: Go for SysAdmins - LISA 2015

Hello World - code// Simple Hello World (1)package main // (2)

import ( // (3) "fmt" // (4))

func main() { // (5) fmt.Println("Welcome to Go!") // (6)}

gettingstarted

Page 25: Go for SysAdmins - LISA 2015

Comments• Can be on any line

• Comment till the end of line - //

• Or use /* */ for multiline comments

• LINE1 : Simple comment

// Simple Hello World (1)

gettingstarted

Page 26: Go for SysAdmins - LISA 2015

Go Package Model• Packages break up pieces of work

• Each file requires package definition

• Multiple files can be in the same package

• import tells Go to use another package

• Definitions inside a package can be internal only or allowed to be used externally

• Internal only definitions are named variable name starting with a lowercase character

• External definitions are named starting with an uppercase character

gettingstarted

Page 27: Go for SysAdmins - LISA 2015

Go Package Model• Import name:

• Standard library : just the short name import "fmt"

• Other packages: corresponds to directory name

• import "github.com/cmceniry/gotutorial/mypackage"

• File name inside that directory doesn’t matter as much. All files in a package (in the directory and with the proper package header) will be built together.

• Files in a directory that use a different package header will be ignored.

• Command/executables will always be in package main

gettingstarted

Page 28: Go for SysAdmins - LISA 2015

• LINE2: main package since this is going to be an executable

• LINE3: General import line

• LINE4: Importing fmt package from the standard library

package main // (2)

import ( // (3) "fmt" // (4))

gettingstarted

Page 29: Go for SysAdmins - LISA 2015

main()

• Like most c styled languages, the main function is what is used for executables

• Always of this form

• With go run, this will be the way to set up files

• Likewise package main will always be used for go run

• For now, consider it boilerplate

func main() { // (5)

gettingstarted

Page 30: Go for SysAdmins - LISA 2015

fmt (fuh-um-put)• fmt.Print() : Outputs a line of text. Spaces added between operands.

• fmt.Println() : Mostly the same as above, but adds a newline to the end (also has some subtle differences on spacing between operands).

• fmt.Printf() : Output formatted text (only does newline if you include \n). If you really care about the output, this is the one to use.

fmt.Println("Welcome to Go!") // (6)

gettingstarted

Page 31: Go for SysAdmins - LISA 2015

// Simple Hello World (1)package main // (2)

import ( // (3) "fmt" // (4))

func main() { // (5) fmt.Println("Welcome to Go!") // (6)}

[vagrant@g4sa helloworld]$ go run helloworld.goWelcome to Go![vagrant@g4sa gotutorial]$

gettingstarted

Page 32: Go for SysAdmins - LISA 2015

Control Structures

Page 33: Go for SysAdmins - LISA 2015

var, :=• All identifiers/variables have to be defined before you can use them (or defined

_when_ you use them).

"var" name type ["=" initialvalue]

• Can also use the "short variable declaration" :=

• Complier infers the type

• More idiomatic

• Can’t redeclare a variable inside the same scope

var line string = "my string"

line := "my string"

var

Page 34: Go for SysAdmins - LISA 2015

_ - The Blank Identifier• Used if you want to ignore a result or value

• In Go philosophy, you must be explicit about it (declare what you use and what you don’t use)

• Use for ignoring errors, array/slice/map indexes

_, otherresult := myFunc()

var

Page 35: Go for SysAdmins - LISA 2015

if"if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ]

• Simple two branch conditional (if/else)

• Has optional simple statement

• Heavily used for call and error checking

• The scope of the variables in SimpleStmt continue till the end of the if block including the else and nested if statements

• Watch out for trying to call/error check and use it later

• Watch out for redeclaring and expecting them to be the same

if

Page 36: Go for SysAdmins - LISA 2015

if• Basic expression (1 == 1)

• Expression (err != nil) with Simple Statement (err := myFunc())

• Expression with Else

if err := myFunc(); err != nil {

if 1 == 1 {

if err == nil {} else {

if

Page 37: Go for SysAdmins - LISA 2015

err• Not a language construct so much as a language convention

• Most functions return an error indicator

• Used for normal errors

• It’s bad form to not check for errors

err

Page 38: Go for SysAdmins - LISA 2015

panic/recover• panic is used for fatal errors

• Not to be used for normal failures

• Will be caught by runtime and exit process with stack trace

• Can be caught like exceptions with recover, but only do this if you really know what you’re doing - not normal go

if err != nil { panic(err)}

panic

Page 39: Go for SysAdmins - LISA 2015

for• Go has a single looping control word

for [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ]

• InitStmt : Setups up loop

• Condition : Checked to exit loop

• PostStmt : Executed after every pass through the loop

• Some sections are optional

• Other forms - see range in maps and arrays/slices

for

Page 40: Go for SysAdmins - LISA 2015

for• Traditional for loop

• While loop

for x := 0 ; x < 10 ; x ++ {

x := 0for x < 10 { x += 1

for

Page 41: Go for SysAdmins - LISA 2015

Infinite for, break• Infinite repeat

• Can get out with a breakx := 0for { if x > 10 { break } x += 1

for {

for

Page 42: Go for SysAdmins - LISA 2015

continue• Can also skip to the next iteration of the loop with continue

• PostStmt is run after continue

for count := 0; true; count += 1 { if err := check() { continue }

for

Page 43: Go for SysAdmins - LISA 2015

• Identifier, argument(s), return value(s), body

"func" FunctionName Signature FunctionBody

Signature = "(" [ParamIdentifier Type ["," ParamIdentifier Type]+] ")" [Type ["," Type]+]

FunctionBody = "{" [Statements]+ "}"

func

func

func AFunc(val1 int64, val2 float64) bool {

FunctionName Signature Start of FunctionBody

Page 44: Go for SysAdmins - LISA 2015

func• Can have multiple return values, not just one

• Common pattern is to return value with error info

• Exits at end of body or with return

• If return types declared in signature, must be returned

• If return types not declared, can't be passed with return

• return can be (almost) anywhere in body

• Package exporting name rules apply (capitalize if you want it available outside)

func

Page 45: Go for SysAdmins - LISA 2015

func• Functions are pass by value

• A copy of each parameter is made and passed into the function

• If you update the value inside of the function, nothing happens outside (see pointers)

Page 46: Go for SysAdmins - LISA 2015

func - examplesfunc noop()

func funca(stra string) string

func concat(stra string, strb string) string

Can combine similar parameter types if they’re in the same order:

func concat(stra, strb string) string

func read(filename string) (int, string, error)

Multiple return values: # of bytes read, actual bytes as string, error

func

Page 47: Go for SysAdmins - LISA 2015

Variadic Functions• Functions which take a variable number of parameters

• Must be the final parameter

• Denoted with ... preceding the last argument type

func Printf(format string, a …string) string

fmt.Printf("%s%s", "string1", "string2")fmt.Printf("%s%s%s%s", "string1", "string2", "string3", "string4")

variadic

Page 48: Go for SysAdmins - LISA 2015

Variadic Functions• Flip the behavior of the parameters when calling variadic functions

• Supply a slice in place of a variadic parameter

• Only allowable for the variadic - final - parameter

func Printf(format string, a …string) stringfmt.Printf("%s%s%s%s%s", "string1", "string2", "string3", "string4")

args := []string{"string1", "string2", "string3", "string4"}fmt.Printf("%s%s%s%s", args...)

variadic

Page 49: Go for SysAdmins - LISA 2015

switch• Go’s switch/case statement

• Matches only one selection

• default catchall for anything that doesn’t match - not required

switch

Page 50: Go for SysAdmins - LISA 2015

switch• Typically operates on a variable value

switch x {case 1: fmt.Println("one")case 2: fmt.Println("two")default: fmt.Println("other")}

switch

Page 51: Go for SysAdmins - LISA 2015

switch• Can operate unbound to a value (collapsed if/else chain)

switch {case x < 0: fmt.Println("negative")case 0 >= x && x <= 10: fmt.Println("single digit")case x > 10: fmt.Println("> 10")}

switch

Page 52: Go for SysAdmins - LISA 2015

switch• Can match multiple values

switch x {case 1,2,3,4,5,6,7,8,9: fmt.Println("single digit")default: fmt.Println("other")}

switch

Page 53: Go for SysAdmins - LISA 2015

switch - fallthrough• fallthrough used in the case where you want the following section to

be executed - even if it doesn’t match switch x {case 1,2,3,4,5,6,7,8,9: fmt.Println("single digit") fallthrough;default: fmt.Println("other")}

switch

Page 54: Go for SysAdmins - LISA 2015

switch - break• break used to exit out of a switch statement

switch x {case 1,2,3,4,5,6,7,8,9: fmt.Println("single digit") if x == 6 { break } fallthrough;default: fmt.Println("anything other than 6")}

switch

Page 55: Go for SysAdmins - LISA 2015

defer• Guarantees will execute after leaving this scope

• Used to clean up open resources

file := os.Open("data")defer file.Close()// Operate on file knowing that it’ll close eventually// regardless of how we leaveif a { return }if b { panic("Error") }return

defer

Page 56: Go for SysAdmins - LISA 2015

Data Structures

Page 57: Go for SysAdmins - LISA 2015

Go Types• Every variable has a Type

• Can represent an actual memory structure

• Or a behavior contract (where Go dynamics come from)

• Multiple categories of types

• First look at traditional data types

• Boolean(bool): true, false

• Numeric

• String(string): immutable series of bytes

• len(mystring): Builtin function that returns the mystring’s size

• stringa+stringb: Creates a third string

• Can create user defined types

• type mytype uint32

typeintro

Page 58: Go for SysAdmins - LISA 2015

Numeric Types• uint8 the set of all unsigned 8-bit integers (0 to 255)

• uint16 the set of all unsigned 16-bit integers (0 to 65535)

• uint32 the set of all unsigned 32-bit integers (0 to 4294967295)

• uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)

• int8 the set of all signed 8-bit integers (-128 to 127)

• int16 the set of all signed 16-bit integers (-32768 to 32767)

• int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)

• int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

• float32 the set of all IEEE-754 32-bit floating-point numbers

• float64 the set of all IEEE-754 64-bit floating-point numbers

• complex64 the set of all complex numbers with float32 real and imaginary parts

• complex128 the set of all complex numbers with float64 real and imaginary parts

• byte alias for uint8

• rune alias for int32

typeintro

Page 59: Go for SysAdmins - LISA 2015

make• Some types have variable memory allocation behind them

• Slice, Map, Channel - more in the corresponding section

• Need some special action to initialize them

• make() function

• Closest Go has to malloc

typeintro

Page 60: Go for SysAdmins - LISA 2015

{}• Composite types (structs, arrays, slices, maps) can be initialized

using the {} form

• Best equivalent to literals

typeintro

a := [] int{1,2,3,4} // slice value [1,2,3,4]b := Point{x,y} // struct Point with x,y

c := 1 // kinda like int64{1}d := 4.5 // kinda like float64{4.5}

Page 61: Go for SysAdmins - LISA 2015

range• Special operator to iterate over matching types

• Slice, Array, Map, Channel (technically string as well)

• Different meaning for each context

• More info in the corresponding section

• Only operates with for loop

typeintro

Page 62: Go for SysAdmins - LISA 2015

Arrays• An array is a numbered sequence of a single type

• E.g. int,int,int,int,int,int,int

• Variable type signature is [size]singletype

• [4]int, [10]string, [2][5]int

• Variable value is allocated at creation with "zero" value for type

array

var a [10]int // [0,0,0,0,0,0,0,0,0,0]var s [3]string // ["", "", ""]

Page 63: Go for SysAdmins - LISA 2015

Arrays• Get size with the len() function

• Indexed by integers 0 thru len(array)-1

• Outside that == panic

fmt.Println(len(a)) // 10

fmt.Println(a[1]) // 0a[1] = 42

array

Page 64: Go for SysAdmins - LISA 2015

Arrays• Safely iterate over entire array : for … range

for index, element := range arrayvar { fmt.Println(index, element)}

array

Page 65: Go for SysAdmins - LISA 2015

Arrays• Arrays are limited in that they are a fixed size

• Arrays are a fixed memory allocation

• This causes issues with function parameters

• How do you use a variable length parameter? ==> Slices

array

Page 66: Go for SysAdmins - LISA 2015

Slices• A subset of an array is a slice

• Basically a reference to which element to start with, and a length

• Type signature is []singletype - NOTE: No size value in the signature

• Why Slices? Separates the interaction to an array from the storage of the array

• Useful when you want to reuse code where the specific length of the array doesn’t matter, only the fact that it is an array of a specific type

• Equivalent to how you treat arrays in ruby, python, perl

slice

Page 67: Go for SysAdmins - LISA 2015

Slices• Created by

• The [:] syntax

• The make function

b := a[5:8]

var c [] intc = make([] int, 10)

slice

Page 68: Go for SysAdmins - LISA 2015

Slices• Reference just like arrays

• Range works as well

for index, element := range arrayvar { fmt.Println(index, element)}

a := make([] int, 10)a[0] = 5fmt.Println(a[0])

slice

Page 69: Go for SysAdmins - LISA 2015

Arrays and Slices• len() is similar to arrays

• Slices also have a cap() - capacity: how many elements the slice can hold

• All slices have an underlying array to them - the slice is a reference

a

bStart Len 3 Cap 5

cStart Len 10 Cap 10

slice

Page 70: Go for SysAdmins - LISA 2015

append• Once a slice is allocated, it’s limited in size due to the underlying

array.

• If you need to grow it, you have to create a new one and copy all values into it.

• Or use internal append function

slice

c := [] int{1,2} // c = [1,2]; cap(c) = 2d := append(c, 3, 4) // d = [1,2,3,4]; cap(c) = 8

Page 71: Go for SysAdmins - LISA 2015

More info on arrays, slices• There are some subtle behaviors here. The underlying

representations can have some gotchas for what really is the slice versus what really is an array.

• Here’re some useful references:

• http://blog.golang.org/go-slices-usage-and-internals

• http://www.golang-book.com/6

slice

Page 72: Go for SysAdmins - LISA 2015

Maps• A map is your traditional key/value structure

• "Unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type."

• var subs map[string]string

• Like hashes in other languages

• Can grow without managing underlying allocation (unlike arrays, slices)

Key Type Element Type

map

Page 73: Go for SysAdmins - LISA 2015

Maps - init• Easiest to initializing using the {} form:

• Note: The comma on the last item is mandatory (nicer on line diffs)

var subs map[string]string = map[string]string{ "loop1": "ASM001", "loop2": "ASM002",}

map

Page 74: Go for SysAdmins - LISA 2015

Maps - init• Initialization can also use the make function

• Or shorter ways:

var subs map[string]stringsubs = make(map[string]string)subs["loop1"] = "ASM001"subs["loop2"] = "ASM002"

subs := make(map[string]string)subs["loop1"] = "ASM001"subs["loop2"] = "ASM002"

map

Page 75: Go for SysAdmins - LISA 2015

Maps - add/remove entries• Once created, add items by referencing key:

• And delete items using delete(mapvar, key):

subs["loop3"] = "ASM003"subs["loop4"] = "ASM004"

delete(subs, "loop3")delete(subs, "loop4")

map

Page 76: Go for SysAdmins - LISA 2015

Maps - get entries• Deference by keys:

• If key doesn’t exist, will get the "zero" value for a type - NO PANIC

element := mapvar["key"]

map

fmt.Println(subs["loop5"])// Prints ""

Page 77: Go for SysAdmins - LISA 2015

Maps - check for entries• Check entries using multi-response deference

• Commonly used in if SimpleStatement:

map

if element, present := mapvar["key"]; present {

value, present := mapvar["loop5"]// value = ""// present = false

Page 78: Go for SysAdmins - LISA 2015

Maps - iterate over entries• Use range to iterate over entire map

map

for key, element := range mapvar { fmt.Println(key, element)}

Page 79: Go for SysAdmins - LISA 2015

Structs• Used to create new composite types - meaningful combinations of other

types

• Internal types are "fields"

• Can be used like any other type when defined (e.g. function parameters)

type MyType struct { MyItem string MyCount uint32}

struct

Page 80: Go for SysAdmins - LISA 2015

Structs• Struct can include another struct

• Defines MyType2 with fields of MyType as well

type MyType2 struct { MyType MyCount uint32}

struct

Page 81: Go for SysAdmins - LISA 2015

Structs - get fields• Get fields by referencing to field name

• Note: No need to dereference when using a pointer to a struct

// m is a MyTypem.MyItemm.MyCount// m2 is a MyType2m.MyItemm.MyCountm.MyName

struct

Page 82: Go for SysAdmins - LISA 2015

Structs - set fields• Normally initialized using {} with zero values for field types

• Set values after defining the variablem := MyType{}m.MyItem = "myitem"m.MyCount = 24

struct

Page 83: Go for SysAdmins - LISA 2015

Structs - set fields• Can initialize with values by referencing field names.

• Can skip field names if going in order of struct definition

• Must refer to nested structs as nested types

m := MyType{MyItem: "myitem", MyCount: 24}

m := MyType{"myitem", 24}

m := MyType2{MyType: MyType{"myitem", 24}, "myname"}

struct

Page 84: Go for SysAdmins - LISA 2015

Structs - methods• Functions can be defined which require a struct type to operate on

• Closest to what Go has for OOP

• This really applies to any type, but most commonly seen with structs

func (MyType m) RemoveName() string { ret := m.MyName m.MyName = "" return ret}

struct

Page 85: Go for SysAdmins - LISA 2015

Pointers• A variable is a placeholder for a chunk of memory

• A pointer is a placeholder to the address of that chunk of memory.

• nil is the pointer that points nowhere

• Declare: *type

• Reference: *var - On a pointer to get the value at the address

• Dereference: &var - On a nonpointer to get the value of the address

pointer

Page 86: Go for SysAdmins - LISA 2015

Pointers - Why?• Functions are pass by value : A copy of the value is passed in to the parameter

variable

• If you make changes to the variable inside of the function, it doesn’t impact the original variable

• (To make a long story short…) Sometimes you want to do that; sometimes you don’t.

• Since the pointer is the address and the address is passed by value, it is still pointing to the same spot. When you make changes to the spot that that pointer is pointing at, the underlying data changes.

• If you want to make changes, pass around pointers. If not, continue on as normal.

pointer

Page 87: Go for SysAdmins - LISA 2015

Pointersvar a int, b *inta = 5b = &ac := &a

5a

b 0xc200000018

c 0xc200000018

pointer

Page 88: Go for SysAdmins - LISA 2015

Interfaces• Go’s form of dynamic typing

• Collection of methods which must be satisfied by a type

• versus struct methods which are what satisfy these

• When a variable is declared of an interface type, it’s saying "where used, this variable will be able to handle these methods… somehow"

• The interface is a minimum set of methods. structs can implement more methods, but to use them from an interface variable, you have to explicitly type assert

• All types satisfy the empty interface{} so it can be used anywhere (but always has to be asserted before it can be used)

interface

Page 89: Go for SysAdmins - LISA 2015

Interfaces• Stringer is an interface which says "I can produce a string"

• Any type which satisfies this is valid. It’s up to the actual type to figure out how.

type Stringer interface { String() string}

func (MyType) String() string { return "mytype"}

interface

Page 90: Go for SysAdmins - LISA 2015

Interfaces• A function can have a Stringer interface type as its parameter

• Stringer argument is usually dereferenced somewhere inside - in this case using String()

• Rely on the behavior guarantee that String() will execute

func Printme(Stringer s) { fmt.Println(s.String())}

interface

Page 91: Go for SysAdmins - LISA 2015

Interfaces - Type Assertion• When working with interfaces, it’s sometimes necessary to get back

to the non-interface type.

• Perform a type assertion to convert how the variable is handled in the code (doesn’t make changes to the underlying memory holding the data)

• Needed when calling methods that belong only to the original type

m1 := m.(MyType)

m1.MyTypeOnlyFunc()

interface

Page 92: Go for SysAdmins - LISA 2015

Interface - Check• An invalid type assertion will panic.

• Check for a bad assertion with an extended form

• ok will be true if m can be asserted into MyType; false otherwise.

• Useful with if statements

m1, ok := m.(MyType)

if m1, ok := m.(MyType); ok { fmt.Println("Successfully asserted to MyType")

interface

Page 93: Go for SysAdmins - LISA 2015

Interfaces - Type Switch• A type switch is a collection of type assertion checks - much like a

switch is a collection of if/else blocks

• Has default statement for catchall

switch m.(type) {case nil: fmt.Println("m is nil")case MyType: fmt.Println("m is MyType")default: fmt.Println("Unhandled type for m")}

interface

Page 94: Go for SysAdmins - LISA 2015

Function Type• Functions are first class citizens in Go’s types

• Can define custom types based on function signature

• Any operation on a type, works on function types. Even using a function as a method receiver

type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {

functiontype

Page 95: Go for SysAdmins - LISA 2015

Anonymous Functions• Can use func definition anywhere a function is expected

• Commonly used as callback handlers

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the web server")})

Page 96: Go for SysAdmins - LISA 2015

Concurrency

Page 97: Go for SysAdmins - LISA 2015

Concurrency• Go has 3 constructs to help with safe concurrency

• Goroutines : Go’s thread model

• Channels : Method to synchronize between Goroutines

• Select : Method to multiplex between different channel readers/writers

concurrencyintro

Page 98: Go for SysAdmins - LISA 2015

Go Concurrency Articles• http://blog.golang.org/pipelines

• http://dave.cheney.net/2013/04/30/curious-channels

• http://rcrowley.org/articles/golang-graceful-stop.html

• http://stackoverflow.com/questions/6807590/how-to-stop-a-goroutine

concurrencyintro

Page 99: Go for SysAdmins - LISA 2015

Goroutines• A goroutine is a independent concurrent thread of control within the

same address space

• Ideal for parallelization, and background routines

• Main program control is handled by the main thread running the main() func.

• If main() finishes, the program will exit, and all other threads die

goroutine

Page 100: Go for SysAdmins - LISA 2015

Goroutines• Easy to start

• Can also use anonymous function

go myfunc()

go func() { // background items

goroutine

Page 101: Go for SysAdmins - LISA 2015

Goroutines - Shared memory• Can access any variables which are in scope of function

• Useful at times (listener), race condition at other times

val := 123go func() { val = 456}time.Sleep(1 * time.Second)// val may be 123 or 456 depending on executions

goroutine

Page 102: Go for SysAdmins - LISA 2015

Channels• "Mechanism for two concurrently executing functions to synchronize

execution and communicate by passing a value of a specified element type"

• Building on unix conventions, Go has a built in data passing mechanism

• Behaves like unix pipes - write/read data in order

• Can be used in a variety of ways

• Data flow

• Signaling

channel

Page 103: Go for SysAdmins - LISA 2015

Channels - making, using• Must be made first

• Sending into the channel

• Receiving from the channel

mychan := make(chan int)

mychan <- 5

myvar := <-mychan

channel

Page 104: Go for SysAdmins - LISA 2015

Channels - using• Can use receiver anywhere the content type fits

// Get from channel r and discard<-r// Get from channel r and assign to new variable aa := <-r// Get from channel r and pass into MyFunc functionMyFunc(<-r)// Get from channel r and return from functionreturn <-r

channel

Page 105: Go for SysAdmins - LISA 2015

Channels - direction• Only does one direction

• Sends go into it

• Receives come out of it

• If you want two threads to talk bidirectionally talk to each other, must create two paths

atob := make(chan int)btoa := make(chan int)

channel

Page 106: Go for SysAdmins - LISA 2015

Channels - blocking, depth• Without anything else, a channel will block until the other side has

something

• Senders block until a receiver takes

• Receivers block until a sender transmits

channel

Page 107: Go for SysAdmins - LISA 2015

Channels - blocking, depth• Can create buffered channels so that it will not block until the buffer

is full/empty

• Call make() with a size argument

• Sender can buffer up to size before it blocks

• Receiver can pull buffered values without blocking

mychan := make(chan int, 10) // buffer 10

channel

Page 108: Go for SysAdmins - LISA 2015

Channels - type• Channel is a type of its own and specific to the type of the contents

• E.g. chan int is not the same as chan float

• Channels can be used like other types

channel

// chan as function parameters in definitionfunc MyFunc(chan int incoming, chan bool stop) {// chan being pass into the functiona := make(chan int, 10)b := make(chan bool)MyFunc(a,b)

Page 109: Go for SysAdmins - LISA 2015

select• Multiplex between different channels which may block

• Allows you to handle multiple inputs/outputs without losing time

• Considers a channel ready if it will not block

• Has something on the other end already there

• Or is buffered

select

Page 110: Go for SysAdmins - LISA 2015

select - using• Similar to switch statement - different word but same pattern

• Wrap sends and receives with select and case statements

• Can have default statement if none are readyselect {case <- c1: // receive from channel c1 and discard valuecase val2 := <- c2: // receive from c2 and put into val2case c3 <- 5: // send 5 into c3default: // if no one is ready}

select

Page 111: Go for SysAdmins - LISA 2015

select - timeout• default will execute immediately if all are blocked

• Most of the time, you want a timeout, not an immediate return

• Can use time.After to produce a timeout channel

to := time.After(5 * time.Second)select {case <- c1: // Got a value before the timeoutcase <- to: // Got a timeout}

select

Page 112: Go for SysAdmins - LISA 2015

Additional References• http://goforsystemadministration.com/

• http://golang.org/ref/spec

• http://golang.org/doc/effective_go.html

• http://golang.org/doc/faq

• http://tour.golang.org/

• http://gobyexample.com

• http://blog.golang.org/

• https://gophercasts.io/

• https://gocasts.io/