Skip to content

fstab/go-programming-for-java-developers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

9 Commits

Repository files navigation

Go Programming for Java Developers

Notes for my Go programming workshop.

1 About Me

2 Resources

3 About Go

  • Created at Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson
  • Main design goal: Simplicity (not many features)
  • Main purpose: System tools programming

4 Go for Java Developers

Go is very similar to Java

  • C-like Syntax
  • Strongly typed
  • Packages, Imports
  • ...

Java developers will learn Go very quickly.

5 Installation

Java:

  • Download and extract JDK.
  • Set environment variable JAVA_HOME to JDK directory.
  • Include $JAVA_HOME/bin in PATH.

Go:

  • Download and extract Go.
  • Set environment variable GOROOT to Go directory (default /usr/local/go or C:\Go).
  • Include $GOROOT/bin in PATH.

Optional (not needed in this workshop): Set GOPATH to workspace, like $HOME/go.

6 Exercise

  • Install go
  • Run the following commands
go go help go help run go help fmt

7 Go Tool

The go command is more like mvn than like javac.

go get ... <-- download from github, bitbucket, etc. go test ... <-- like 'mvn test' go install ... <-- install binary to $GOPATH/bin 

8 Go Directory Structure

Like mvn, the go command assumes a defined directory structure:

$GOPATH/bin <- compiled executables $GOPATH/pkg <- compiled libraries $GOPATH/src/github.com/... <- source code $GOPATH/src/bitbucket.org/... <- source code $GOPATH/src/... <- source code 

In real-world go development, you run go install to compile the source code and create an executable in $GOPATH/bin.

However, in this workshop we use go run, which is a shortcut to quickly run a single go file. The go run command does not require the directory structure above.

9 Hello, World!

package main import ( "fmt" ) funcmain(){fmt.Printf("Hello, World!\n") }

10 Exercise

  • Create a file hello.go containing the hello world source code.
  • Format and run the program:
go fmt hello.go go run hello.go

Read the documentation of the fmt package and the Printf call

go doc fmt go doc fmt.Printf

11 Hello, <name>!

  • os.Args is an []string (like String[] in Java)
  • len(os.Args) returns the number of elements (like arr.length in Java)
package main import ( "fmt""os" ) funcmain(){iflen(os.Args) !=2{fmt.Printf("Usage: ./hello <name>\n") return } fmt.Printf("Hello, %v\n", os.Args[1]) }

12 os.Args[0]

  • os.Args[0] is the name of the executable
  • Example: ./hello Fabian:
    • os.Args[0]: ./hello
    • os.Args[1]: Fabian
  • With go run hello.go Fabian, the program will be compiled to an executable in a temporary directory, this temporary executable is executed. -> os.Args[0] is the path to the temporary executable created by go run.

13 Loops

Use of for like Java's for

fori:=0; i<10; i++{fmt.Printf("%v\n", i) }

Use of for like Java's while

i:=0fori<10{fmt.Printf("%v\n", i) i++ }

Use of for like Java's while(true)

i:=0for{ifi>=10{break } fmt.Printf("%v\n", i) i++ }

14 Exercise

Write a program that says hello to multiple people:

> go run hello.go Fabian Thomas ChristianHello, Fabian!Hello, Thomas!Hello, Christian!

15 Variables

Variable declaration

varainta=3

Variable declaration with initializer

vara=3

Short variable declaration

a:=3

Declaring multiple variables

var ( a, bintcstring ) vara, b, c=3, 4, "hello"

Constants (like final in Java)

consta=3

16 Functions

funcadd(aint, bint) int{returna+b }
funcadd(a, bint) int{returna+b }
funcaddAndMult(a, bint) (int, int){returna+b, a*b } funcmain(){sum, product:=addAndMult(3, 7) fmt.Printf("sum = %v, product = %v\n", sum, product) }

17 Function Example

package main import"fmt"funcswap(x, ystring) (string, string){returny, x } funcmain(){a, b:=swap("world", "hello") fmt.Printf("%v, %v\n", a, b) }

18 Error Handling with Multiple Return Values

package main import ( "fmt""strconv""os" ) funcmain(){// We assume that len(os.Args) >= 2n, err:=strconv.Atoi(os.Args[1]) iferr!=nil{fmt.Printf("Error: %v is not a valid number.\n", os.Args[1]) return } fmt.Printf("Your number is %v\n", n) }

Go's nil is like Java's null.

19 Ignoring Return Values

In go it's a syntax error if a variable is declared but not used:

funcmain(){sum, product:=addAndMult(3, 7) fmt.Printf("sum = %v\n", sum) }

Syntax error, because variable product is declared but not used.

To explicitly ignore a return value, use _:

funcmain(){sum, _:=addAndMult(3, 7) fmt.Printf("sum = %v\n", sum) }

20 Exercise

Write a program that prints the first n Fibonacci numbers.

> go run fibonacci.go 101 1 2 3 5 8 13 21 34 55

21 Bonus Exercise

From http://tour.golang.org

As a simple way to play with functions and loops, implement the square root function using Newton's method.

In this case, Newton's method is to approximate Sqrt(x) by picking a starting point z and then repeating:

Newton's method formula

To begin with, just repeat that calculation 10 times and see how close you get to the answer for various values (1, 2, 3, ...).

Next, change the loop condition to stop once the value has stopped changing (or only changes by a very small delta). See if that's more or fewer iterations. How close are you to the math.Sqrt?

Hint: to declare and initialize a floating point value, give it floating point syntax or use a conversion:

z := float64(1)

z := 1.0

22 Deferred Methods

package main import ( "bufio""fmt""os" ) constpath="./hello.txt"funcmain(){file, err:=os.Open(path) iferr!=nil{fmt.Printf("failed to open file: %v\n", err) os.Exit(-1) } deferfile.Close() reader:=bufio.NewReader(file) for{line, err:=reader.ReadString('\n') iferr!=nil{break } fmt.Printf("%v", line) } }

23 Exercise

Modify the hello world program and add some deferred method calls, like

deferfmt.Printf("defer 1\n") deferfmt.Printf("defer 2\n") deferfmt.Printf("defer 3\n")

Figure out the order in which these calls are executed.

24 Pointers

package main import"fmt"funcdouble(iint){i=i*2 } funcmain(){i:=2double(i) fmt.Printf("i = %v\n", i) }

Result: i = 2

package main import"fmt"funcdouble(i*int){*i=*i*2 } funcmain(){i:=2double(&i) fmt.Printf("i = %v\n", i) }

Result: i = 4

25 Structs

package main import"fmt"typerectanglestruct{heightfloat64widthfloat64 } funcmain(){square:=&rectangle{height: 4.0, width: 4.0, } fmt.Printf("square has area of %v\n", square.height*square.width) }
  • A struct is like a final class in Java.
  • Variables starting with an upper case letter are public, variables starting with a lower case letter are package private.

26 Methods

package main import"fmt"typerectanglestruct{heightfloat64widthfloat64 } func (r*rectangle) area() float64{returnr.width*r.height } funcmain(){square:=&rectangle{height: 4.0, width: 4.0, } fmt.Printf("square has area of %v\n", square.area()) }

27 Exercise

Define struct circle with variable radius that also has a method area().

Hint: go doc math.Pi

28 String Concatenation

Java: Implicit conversion from float64 to String

return"the area is " + s.area();

Go: Explicit string formatting

returnfmt.Sprintf("area is %v", s.area())

29 Interfaces

typeshapeinterface{area() float64 } funcareaInfo(sshape) string{returnfmt.Sprintf("area is %v", s.area()) } funcmain(){c:=&circle{radius: 2.0, } r:=&rectangle{width: 4.0, height: 4.0, } fmt.Printf("circle: %v\n", areaInfo(c)) fmt.Printf("rectangle: %v\n", areaInfo(r)) }

30 Pre-Defined Interfaces

Go has some pre-defined interfaces. The most important ones are:

typeStringerinterface{String() string }

Like Java's toString()

typeerrorinterface{Error() string }

Remember file, err := os.Open(path)? The err is of type error.

31 Exercise

Implement a String() method for rectangle and circle.

The following code:

funcmain(){c:=&circle{radius: 2.0, } r:=&rectangle{width: 4.0, height: 4.0, } fmt.Printf("Shape 1: %v\n", c) fmt.Printf("Shape 2: %v\n", r) }

Should produce the following output:

Shape 1: circle with radius 2 and area 12.566370614359172Shape 2: rectangle with width 4, height 4, and area 16

32 Functional Programming

Example 1: Define an anonymous function and assign it to a variable

package main import"fmt"funcmain(){f:=func(nint) int{return2*n } fmt.Printf("f(21) = %v\n", f(21)) }

Example 2: Pass a function as parameter to another function

package main import"fmt"funcapplyFunction(nint, ffunc(int) int){fmt.Printf("f(%v) = %v\n", n, f(n)) } funcmain(){f:=func(nint) int{return2*n } applyFunction(21, f) }

33 Arrays & Slices

Java Arrays:

intsize = 10; int[] arr = newint[size];

Go Slices:

size:=10slice:=make([]int, size)

Iterate over a slice:

fori, val:=rangeslice{fmt.Printf("slice[%v] = %v\n", i, val) }

34 Arrays & Slices Example

package main import"fmt"funccreateSlice(sizeint) []int{slice:=make([]int, size) fori:=0; i<size; i++{slice[i] =i+1 } returnslice } funcapplyFunction(slice []int, ffunc(int) int){fori, n:=rangeslice{slice[i] =f(n) } } funcmain(){f:=func(nint) int{return2*n } slice:=createSlice(10) fmt.Printf("%v\n", slice) applyFunction(slice, f) fmt.Printf("%v\n", slice) }

Result:

[1 2 3 4 5 6 7 8 9 10][2 4 6 8 10 12 14 16 18 20]

35 Slicing

Example 1:

slice:=createSlice(10) fmt.Printf("%v\n", slice) part:=slice[3:7] applyFunction(part, f) fmt.Printf("%v\n", slice)

Result:

[1 2 3 4 5 6 7 8 9 10][1 2 3 8 10 12 14 8 9 10]

Example 2:

slice:=createSlice(10) fmt.Printf("%v\n", slice) firstHalf:=slice[:len(slice)/2] applyFunction(firstHalf, f) fmt.Printf("%v\n", slice) secondHalf:=slice[len(slice)/2:] applyFunction(secondHalf, f) fmt.Printf("%v\n", slice)

Result:

[1 2 3 4 5 6 7 8 9 10][2 4 6 8 10 6 7 8 9 10][2 4 6 8 10 12 14 16 18 20]

36 Exercise

Write a function combine() such that

funcmain(){add:=func(a, bint) int{returna+b } mult:=func(a, bint) int{returna*b } slice:=createSlice(10) fmt.Printf("add(1..10)=%v\n", combine(slice, add)) fmt.Printf("mult(1..10)=%v\n", combine(slice, mult)) }

Prints the following output

add(1..10)=55mult(1..10)=3628800

Bonus task: Implement two versions of combine(): one with a for loop, and one recursive version without using for.

37 Multithreading

package main import ( "fmt""time" ) funcsay(sstring){fori:=0; i<5; i++{time.Sleep(100*time.Millisecond) fmt.Printf("%v\n", s) } } funcmain(){gosay("world") say("hello") }

38 Channels

package main import ( "time""fmt" ) funcproduceNumber(cchanint){time.Sleep(10*time.Second) c<-3 } funcmain(){c:=make(chanint) goproduceNumber(c) n:=<-cfmt.Printf("n = %v\n", n) }

39 Loop over Data Read from Channel

package main import ( "time""fmt" ) funcproduceNumber(cchanint){fori:=0; i<10; i++{time.Sleep(1*time.Second) c<-i+1 } close(c) } funcmain(){c:=make(chanint) goproduceNumber(c) forn:=rangec{fmt.Printf("n = %v\n", n) } }

40 Exercise

Re-write the channel examples with two go-routines:

  • One producer routine producing numbers
  • One consumer routine printing numbers to stdout

Terminology: A function running as a background thread is a go-routine.

41 Waiting for termination

package main import ( "time""fmt" ) funcproduceNumbers(cchanint){fori:=0; i<10; i++{time.Sleep(1*time.Second) c<-3 } close(c) } funcconsumeNumbers(cchanint, donechaninterface{}){forn:=rangec{fmt.Printf("n = %v\n", n) } close(done) } funcmain(){c:=make(chanint) done:=make(chaninterface{}) goproduceNumbers(c) goconsumeNumbers(c, done) <-done }

42 Polling on multiple channels with select

chancintchandoneinterface{} select{casen<-c: // do something with ncase<-done: // shut down }

43 Exercise

Implement a deadlock (go-routine A is reading from channel of go-routine B and vice versa) and see what happens.

44 Buffered Channels

  • Write to channel blocks
  • Channels may have capacity
  • Reading from a closed channel returns nil
  • Writing to a closed channel panics

-> Always the producer should close a channel.

45 HTTP Server

package main import ( "fmt""net/http""os" ) funchandler(w http.ResponseWriter, r*http.Request){fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path) } funcmain(){http.HandleFunc("/", handler) err:=http.ListenAndServe("localhost:8000", nil) iferr!=nil{fmt.Fprintf(os.Stderr, "Failed to open Web server on localhost:8080: %v\n", err) } }

46 Exercise

Include a unique number in each response:

  • First response gets number 1
  • Second response gets number 2
  • etc.

Avoid race conditions. Don't communicate through shared memory, use channels!!!

47 Mutexes

From The Go Programming Language, Chapter 1.7:

package main import ( "fmt""log""net/http""sync" ) varmu sync.Mutexvarcountintfuncmain(){http.HandleFunc("/", handler) http.HandleFunc("/count", counter) log.Fatal(http.ListenAndServe("localhost:8000", nil)) } // handler echoes the Path component of the requested URL.funchandler(w http.ResponseWriter, r*http.Request){mu.Lock() count++mu.Unlock() fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path) } // counter echoes the number of calls so far.funccounter(w http.ResponseWriter, r*http.Request){mu.Lock() fmt.Fprintf(w, "Count %d\n", count) mu.Unlock() }

48 Summary

Topics covered in this workshop:

  • control flow: if/else, for
  • functions, error handling, deferred methods
  • pointers, structs, methods, interfaces
  • arrays & slices
  • multithreading

Solution to Exercise 14

package main import ( "fmt""os" ) funcmain(){fori:=1; i<len(os.Args); i++{fmt.Printf("Hello, %v\n", os.Args[i]) } }

Solution to Exercise 20

package main import ( "fmt""os""strconv" ) funcmain(){iflen(os.Args) !=2{fmt.Print("Usage: fibonacci <n>\n") return } n, err:=strconv.Atoi(os.Args[1]) iferr!=nil{fmt.Print("Invalid number.\n") return } fmt.Print("Result:") varprev, cur=0, 1fori:=0; i<n; i++{fmt.Printf(" %v", cur) prev, cur=cur, prev+cur } fmt.Print("\n") }

Solution to Exercise 23

package main import ( "fmt" ) funcmain(){deferfmt.Printf("defer 1\n") deferfmt.Printf("defer 2\n") fmt.Printf("Hello, World!\n") deferfmt.Printf("defer 3\n") }

Solution to Exercise 27

package main import ( "fmt""math" ) typerectanglestruct{heightfloat64widthfloat64 } func (r*rectangle) area() float64{returnr.width*r.height } typecirclestruct{radiusfloat64 } func (c*circle) area() float64{returnmath.Pi*c.radius*c.radius } funcmain(){r:=&rectangle{height: 4.0, width: 4.0, } c:=&circle{radius: 2.0, } fmt.Printf("square has area of %v\n", r.area()) fmt.Printf("circle has area of %v\n", c.area()) }

Solution to Exercise 31

package main import ( "fmt""math" ) typerectanglestruct{heightfloat64widthfloat64 } func (r*rectangle) area() float64{returnr.width*r.height } typecirclestruct{radiusfloat64 } func (c*circle) area() float64{returnmath.Pi*c.radius*c.radius } func (r*rectangle) String() string{returnfmt.Sprintf("rectangle with width %v, height %v, and area %v", r.width, r.height, r.area()) } func (c*circle) String() string{returnfmt.Sprintf("circle with radius %v and area %v", c.radius, c.area()) } funcmain(){c:=&circle{radius: 2.0, } r:=&rectangle{width: 4.0, height: 4.0, } fmt.Printf("Shape 1: %v\n", c) fmt.Printf("Shape 2: %v\n", r) }

Solution to Exercise 36

package main import"fmt"// for loopfunccombine1(slice []int, ffunc(int, int) int) int{result:=slice[0] fori:=1; i<len(slice); i++{result=f(result, slice[i]) } returnresult } // recursivefunccombine2(slice []int, ffunc(int, int) int) int{iflen(slice) ==1{returnslice[0] } iflen(slice) ==2{returnf(slice[0], slice[1]) } left:=combine2(slice[:len(slice)/2], f) right:=combine2(slice[len(slice)/2:], f) returnf(left, right) } funccreateSlice(sizeint) []int{slice:=make([]int, size) fori:=0; i<size; i++{slice[i] =i+1 } returnslice } funcmain(){add:=func(a, bint) int{returna+b } mult:=func(a, bint) int{returna*b } slice:=createSlice(10) fmt.Printf("for loop:\n") fmt.Printf("add(1..10)=%v\n", combine1(slice, add)) fmt.Printf("mult(1..10)=%v\n", combine1(slice, mult)) fmt.Printf("\nrecursive:\n") fmt.Printf("add(1..10)=%v\n", combine2(slice, add)) fmt.Printf("mult(1..10)=%v\n", combine2(slice, mult)) }

Solution to Exercise 40

package main import ( "time""fmt" ) funcproduceNumbers(cchanint){fori:=0; i<10; i++{time.Sleep(1*time.Second) c<-i } close(c) } funcconsumeNumbers(cchanint){forn:=rangec{fmt.Printf("n = %v\n", n) } } funcmain(){c:=make(chanint) goproduceNumbers(c) goconsumeNumbers(c) time.Sleep(12*time.Second) }

Solution to Exercise 43

package main funcmain(){c1, c2:=make(chanint), make(chanint) done:=make(chaninterface{}) gofunc(){<-c1// read from c1c2<-42// write to c2close(done) }() gofunc(){<-c2// read from c2c1<-42// write to c1<-done }() <-done }

Solution to Exercise 46

package main import ( "fmt""net/http""os" ) varc=make(chanint) funcproducer(){i:=0for{i++c<-i } } funchandler(w http.ResponseWriter, r*http.Request){fmt.Fprintf(w, "Request number is %v. Note that you browser might send two requests per 'reload'.\n", <-c) } funcmain(){goproducer() http.HandleFunc("/", handler) err:=http.ListenAndServe("localhost:8000", nil) iferr!=nil{fmt.Fprintf(os.Stderr, "Failed to open Web server on localhost:8080: %v\n", err) } }

About

Golang Programming Workshop

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published