mv to source

This commit is contained in:
Mark McGranaghan
2012-09-29 13:21:57 -07:00
parent c90760c285
commit 7307c6bb0b
118 changed files with 0 additions and 0 deletions

23
src/002-values/values.go Normal file
View File

@@ -0,0 +1,23 @@
// ## Values
// Go has various value types, including strings,
// different types of numbers, booleans, etc.
package main
import "fmt"
func main() {
// Here are some strings, which can be added together.
fmt.Println("Hello world")
fmt.Println("Hello " + "other")
// Some examples of integers and floats.
fmt.Println("1+1 =", 1+1)
fmt.Println("7.0/3.0 =", 7.0/3.0)
// And booleans, which work as you'd expect.
fmt.Println(true && false)
fmt.Println(true || false)
fmt.Println(!true)
}

8
src/002-values/values.sh Normal file
View File

@@ -0,0 +1,8 @@
$ go run values.go
Hello world
Hello other
1+1 = 2
7.0/3.0 = 2.3333333333333335
false
true
false

View File

@@ -0,0 +1,16 @@
// ## Variables
package main
import "fmt"
func main() {
// `var` declares 1 or more variables. The type comes
// at the end.
var x string = "Hello world"
fmt.Println(x)
// An example of declaring multiple `int` variables.
var a, b int = 1, 2
fmt.Println(a, b)
}

View File

@@ -0,0 +1 @@
go run variables.go

View File

@@ -0,0 +1,11 @@
// ## Inline Assignment
package main
import "fmt"
func main() {
// `x := val` is shorthand for `var x type = val`.
x := "Hello assignment"
fmt.Println(x)
}

View File

@@ -0,0 +1,2 @@
$ go run inline-assignment.go
Hello assignment

View File

@@ -0,0 +1,15 @@
// ## Constants
package main
import "fmt"
// Use `const` to declare a constant value.
// Constants can be ...
const x string = "Hello World"
func main() {
fmt.Println(x)
}
// todo: research

View File

@@ -0,0 +1,2 @@
$ go run constant.go
Hello World

34
src/006-for/for.go Normal file
View File

@@ -0,0 +1,34 @@
// ## For
// `for` is Go's only looping construct. Here are
// two common forms.
package main
import "fmt"
func main() {
// Initialize `i` with `1` and loop until it's 10.
i := 1
for i <= 3 {
fmt.Print(i)
i = i + 1
}
// That type of loop is common. We can do it on one
// line.
for j := 1; j <= 3; j++ {
fmt.Print(j)
}
// `for` without a condition will loop until you
// `return`.
for {
fmt.Println()
return
}
}
// We'll see other `for` forms latter.
// todo: break out of for loop?

2
src/006-for/for.sh Normal file
View File

@@ -0,0 +1,2 @@
$ go run for.go
123123

View File

@@ -0,0 +1,17 @@
// ## If/Else
package main
import "fmt"
func main() {
// If/else is straight-forward. Note that there are no
// enclosing parentheses around the condition.
// Also, there is no ternary operator (`?`) in Go.
fmt.Print("7 is ")
if 7%2 == 0 {
fmt.Println("even")
} else {
fmt.Println("odd")
}
}

View File

@@ -0,0 +1,2 @@
$ go run if-else.go
7 is odd

26
src/008-switch/switch.go Normal file
View File

@@ -0,0 +1,26 @@
// ## Switch
package main
import "fmt"
func main() {
fmt.Print("Write 3 as ")
i := 3
switch i {
case 0:
fmt.Println("zero")
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4:
fmt.Println("four")
case 5:
fmt.Println("five")
default:
fmt.Println("???")
}
}

2
src/008-switch/switch.sh Normal file
View File

@@ -0,0 +1,2 @@
$ go run switch.go
Write 3 as three

12
src/009-arrays/arrays.go Normal file
View File

@@ -0,0 +1,12 @@
// ## Arrays
package main
import "fmt"
func main() {
var x [5]int
x[4] = 100
fmt.Println(x)
fmt.Println(x[4])
}

20
src/010-range/range.go Normal file
View File

@@ -0,0 +1,20 @@
// ## Range
package main
import "fmt"
func main() {
var x [5]float64
x[0] = 98
x[1] = 93
x[2] = 77
x[3] = 82
x[4] = 83
var total float64 = 0
for _, value := range x {
total += value
}
fmt.Println(total / float64(len(x)))
}

16
src/011-slices/slices.go Normal file
View File

@@ -0,0 +1,16 @@
// ## Slices
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3}
slice2 := append(slice1, 4, 5)
fmt.Println(slice1)
fmt.Println(slice2)
slice3 := make([]int, 2)
copy(slice3, slice1)
fmt.Println(slice1)
fmt.Println(slice3)
}

20
src/012-maps/maps.go Normal file
View File

@@ -0,0 +1,20 @@
// ## Maps
package main
import "fmt"
func main() {
x := make(map[string]int)
x["this"] = 7
x["that"] = 13
fmt.Println(x)
fmt.Println(x["this"])
fmt.Println(x["missing"])
fmt.Println(len(x))
delete(x, "that")
fmt.Println(x["that"])
fmt.Println(len(x))
_, present := x["that"]
fmt.Println(present)
}

View File

@@ -0,0 +1,20 @@
// ## Functions
package main
import "fmt"
func avg(vals []float64) float64 {
total := 0.0
for _, val := range vals {
total += val
}
return total / float64(len(vals))
}
func main() {
input := []float64{98, 93, 77, 82, 83}
fmt.Println(input)
output := avg(input)
fmt.Println(output)
}

View File

@@ -0,0 +1,24 @@
// ## Multiple Return Values
// In Go, a function can return multiple values.
// This feature is used often, for example to
// return a result and an error from a function.
package main
import "fmt"
// The `(int, int)` in this signature shows that the
// function returns 2 ints.
func vals() (int, int) {
return 3, 7
}
func main() {
// Use the 2 different return values from the call,
// i.e. multiple assignement.
x, y := vals()
fmt.Println(x)
fmt.Println(y)
}

View File

@@ -0,0 +1,3 @@
$ go run multiple-return-values.go
3
7

View File

@@ -0,0 +1,33 @@
// ## Varadic Functions
// Varadic functions can be called with any number of
// trailing arguments. This is useful if you don't know
// number of arguments that will be needed for a function
// ahead of time.
package main
import "fmt"
// Varadic args are declared with `...type` and
// passed in as a slice.
func add(nums ...int) int {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
// Varadic functions can be called in the usual way.
fmt.Println(add(1, 2))
fmt.Println(add(1, 2, 3))
// If you already have multiple args in a slice,
// apply them to a varadic function using `
// func(slice...)`.
nums := []int{1, 2, 3, 4}
fmt.Println(add(nums...))
}

View File

@@ -0,0 +1,4 @@
$ go run varadic-functions.go
[1 2] 3
[1 2 3] 6
[1 2 3 4] 10

View File

@@ -0,0 +1,22 @@
// ## Closures
package main
import "fmt"
func makeEvenGenerator() func() uint {
i := uint(0)
return func() uint {
i += 2
return i
}
}
func main() {
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())
}
// todo: note example of first-class functions.

View File

@@ -0,0 +1,16 @@
// ## Recursion
package main
import "fmt"
func factorial(x uint) uint {
if x == 0 {
return 1
}
return x * factorial(x-1)
}
func main() {
fmt.Println(factorial(7))
}

18
src/018-defer/defer.go Normal file
View File

@@ -0,0 +1,18 @@
// ## Defer
package main
import "fmt"
func first() {
fmt.Println("1st")
}
func second() {
fmt.Println("2nd")
}
func main() {
defer second()
first()
}

13
src/019-panic/panic.go Normal file
View File

@@ -0,0 +1,13 @@
// ## Panic
// A `panic` means something went unexpectedly wrong.
// Mostly we use it to fail fast on errors that
// shouldn't occur during normal operation.
package main
func main() {
// We'll use panic throught this book to check for
// unexpected errors. This is the only program in the
// book designed to panic.
panic("O noes")
}

7
src/019-panic/panic.sh Normal file
View File

@@ -0,0 +1,7 @@
$ go run 26-panic.go
panic: O noes
goroutine 1 [running]:
main.main()
/.../src/26-panic.go:4 +0x47
...

View File

@@ -0,0 +1,16 @@
// ## Pointers
package main
import "fmt"
func zero(xPtr *int) {
*xPtr = 0
}
func main() {
x := 5
fmt.Println(x)
zero(&x)
fmt.Println(x)
}

17
src/021-new/new.go Normal file
View File

@@ -0,0 +1,17 @@
// ## New
package main
import "fmt"
func one(xPtr *int) {
*xPtr = 1
}
func main() {
xPtr := new(int)
fmt.Println(xPtr)
fmt.Println(*xPtr)
one(xPtr)
fmt.Println(xPtr)
fmt.Println(*xPtr)
}

View File

@@ -0,0 +1,24 @@
// ## Structs
package main
import "fmt"
type Circle struct {
x, y, r float64
}
func main() {
cEmptyPtr := new(Circle)
fmt.Println(cEmptyPtr)
fmt.Println(*cEmptyPtr)
cValue := Circle{x: 1, y: 2, r: 5}
fmt.Println(&cValue)
fmt.Println(cValue)
cOrdered := Circle{1, 2, 5}
fmt.Println(cOrdered)
}
// todo: add field access

View File

@@ -0,0 +1,39 @@
// ## Methods
package main
import "fmt"
import "math"
type Circle struct {
x, y, r float64
}
func (c *Circle) area() float64 {
return math.Pi * c.r * c.r
}
type Rectangle struct {
x1, y1, x2, y2 float64
}
func distance(x1, y1, x2, y2 float64) float64 {
a := x2 - x1
b := y2 - y1
return math.Sqrt(a*a + b*b)
}
func (r *Rectangle) area() float64 {
l := distance(r.x1, r.y1, r.x1, r.y2)
w := distance(r.x1, r.y1, r.x2, r.y1)
return l * w
}
func main() {
circle := Circle{x: 0, y: 3, r: 5}
fmt.Println(circle.area())
rectangle := Rectangle{x1: 3, x2: 10, y1: 5, y2: 7}
fmt.Println(rectangle.area())
}
// todo: pointer vs value receivers

View File

@@ -0,0 +1,56 @@
// ## Embedding
package main
import "math"
import "fmt"
type Shape interface {
area() float64
}
type Circle struct {
x, y, r float64
}
func (c *Circle) area() float64 {
return math.Pi * c.r * c.r
}
type Rectangle struct {
x1, y1, x2, y2 float64
}
func distance(x1, y1, x2, y2 float64) float64 {
a := x2 - x1
b := y2 - y1
return math.Sqrt(a*a + b*b)
}
func (r *Rectangle) area() float64 {
l := distance(r.x1, r.y1, r.x1, r.y2)
w := distance(r.x1, r.y1, r.x2, r.y1)
return l * w
}
func totalArea(shapes ...Shape) float64 {
var area float64
for _, s := range shapes {
area += s.area()
}
return area
}
func main() {
circle := Circle{x: 0, y: 3, r: 5}
rectangle := Rectangle{x1: 3, x2: 10, y1: 5, y2: 7}
area := 0.0
for _, s := range []Shape{&circle, &rectangle} {
area += s.area()
}
fmt.Println(area)
}
// todo: is this named wrong?
// todo: note about embedding access

View File

@@ -0,0 +1,9 @@
// ## Interfaces
package main
import "fmt"
type Shape interface {
area() float64
}

27
src/026-errors/errors.go Normal file
View File

@@ -0,0 +1,27 @@
// ## Errors
package main
import (
"errors"
"fmt"
)
func myFun(arg int) (int, error) {
if arg == 42 {
return -1, errors.New("Can't work with 42")
}
return arg + 3, nil
}
func main() {
r, _ := myFun(7)
fmt.Println(r)
_, e := myFun(42)
fmt.Println(e)
}
// todo: custom errors
// todo: data conveying errors

View File

@@ -0,0 +1,22 @@
// ## OK Guards
package main
import "fmt"
func main() {
x := make(map[string]string)
x["here"] = "yes"
if name, ok := x["?"]; ok {
fmt.Println(name)
} else {
fmt.Println("miss")
}
if name, ok := x["here"]; ok {
fmt.Println(name)
}
}
// todo: note about use with errors

View File

@@ -0,0 +1,17 @@
// ## Goroutines
package main
import "fmt"
func f(n int) {
for i := 0; i < 10; i++ {
fmt.Println(n, ":", i)
}
}
func main() {
go f(0)
var input string
fmt.Scanln(&input)
}

View File

@@ -0,0 +1,26 @@
// ## Concurrent Goroutines
package main
import "time"
import "math/rand"
import "fmt"
func f(n int) {
for i := 0; i < 10; i++ {
fmt.Println(n, ":", i)
time.Sleep(time.Millisecond * time.Duration(rand.Intn(150)))
}
}
func main() {
for i := 0; i < 5; i++ {
f(i)
}
fmt.Println()
for i := 0; i < 5; i++ {
go f(i)
}
var input string
fmt.Scanln(&input)
}

View File

@@ -0,0 +1,12 @@
// ## Channels
package main
import "fmt"
func main() {
var messages chan string = make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}

View File

@@ -0,0 +1,12 @@
// ## Channel Buffering
package main
import "fmt"
func main() {
var messages chan string = make(chan string, 1)
messages <- "ping"
msg := <-messages
fmt.Println(msg)
}

View File

@@ -0,0 +1,37 @@
// ## Channel Directions
package main
import "fmt"
func pinger(pings chan<- string) {
for i := 0; i <= 10; i++ {
pings <- "ping"
}
}
func ponger(pings <-chan string, pongs chan<- string) {
for {
<-pings
pongs <- "pong"
}
}
func printer(pongs <-chan string) {
for {
msg := <-pongs
fmt.Println(msg)
}
}
func main() {
var pings chan string = make(chan string)
var pongs chan string = make(chan string)
go pinger(pings)
go ponger(pings, pongs)
go printer(pongs)
var input string
fmt.Scanln(&input)
}

View File

@@ -0,0 +1,32 @@
// ## Synchronization
// We can use channels to synchronize execution
// accross goroutines. Here's an example of waiting
// for another goroutine to finish.
package main
import "fmt"
import "time"
// The `done` channel will be used for
// synchronization.
func worker(done chan<- bool) {
fmt.Print("Working...")
time.Sleep(time.Second)
fmt.Println(" done")
// Send a value to notify that the work is done.
done <- true
}
func main() {
// Start a worker goroutine, give it the channel to
// notify on.
done := make(chan bool, 1)
go worker(done)
// Block until we can receive a value from the worker
// over the channel.
<-done
}

View File

@@ -0,0 +1,6 @@
$ go run synchronization.go
Working... done
# If you commented out the `<- done` line, the
# program would exit before the `worker` even
# started.

34
src/034-select/select.go Normal file
View File

@@ -0,0 +1,34 @@
// ## Select
package main
import "time"
import "fmt"
func main() {
c1 := make(chan string)
c2 := make(chan string)
d := make(chan bool, 1)
go func() {
time.Sleep(time.Second * 1)
c1 <- "from 1"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "from 2"
}()
go func() {
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println(msg1)
case msg2 := <-c2:
fmt.Println(msg2)
}
}
d <- true
}()
<-d
}

View File

@@ -0,0 +1,27 @@
// ## Timeouts
package main
import "time"
import "fmt"
func main() {
c := make(chan string)
d := make(chan bool, 1)
go func() {
time.Sleep(time.Millisecond * 1500)
c <- "ready"
}()
go func() {
select {
case msg := <-c:
fmt.Println(msg)
case <-time.After(time.Millisecond * 1000):
fmt.Println("timeout")
}
d <- true
}()
<-d
}

View File

@@ -0,0 +1,26 @@
// ## Scatter-Gather
package main
import "sync"
import "time"
import "math/rand"
import "fmt"
func main() {
times := new([20]int)
wait := new(sync.WaitGroup)
for i := 0; i < 20; i++ {
n := i
wait.Add(1)
go func() {
opTime := rand.Intn(2000)
time.Sleep(time.Duration(opTime) * time.Millisecond)
fmt.Println(n)
times[n] = opTime
wait.Done()
}()
}
wait.Wait()
fmt.Println(*times)
}

View File

@@ -0,0 +1,15 @@
// ## Rate Limiting
package main
import "time"
import "fmt"
func main() {
throttle := time.Tick(time.Millisecond * 200)
for {
<-throttle
go fmt.Println("rate-limited action")
}
}
// todo: credit http://code.google.com/p/go-wiki/wiki/RateLimiting

View File

@@ -0,0 +1,31 @@
// ## Worker Pools
package main
import "time"
func main() {
jobs := make(chan int, 100)
acks := make(chan bool, 100)
for w := 0; w < 10; w++ {
go func() {
for j := range jobs {
println("worker", w, "processing job", j)
time.Sleep(time.Millisecond * 150)
acks <- true
}
}()
}
for j := 0; j < 100; j++ {
jobs <- j
}
for a := 0; a < 100; a++ {
<-acks
}
println("all done")
}
// todo: broken

22
src/039-timers/timers.go Normal file
View File

@@ -0,0 +1,22 @@
// ## Timers
package main
import "time"
import "fmt"
func main() {
timer1 := time.NewTimer(time.Second)
<-timer1.C
fmt.Println("Timer 1 expired")
stop1 := timer1.Stop()
fmt.Println("Timer 2 stopped:", stop1)
timer2 := time.NewTimer(time.Second)
go func() {
<-timer2.C
fmt.Println("Timer 2 expired")
}()
stop2 := timer2.Stop()
fmt.Println("Timer 2 stopped:", stop2)
}

4
src/039-timers/tiners.sh Normal file
View File

@@ -0,0 +1,4 @@
$ go run timers.go
Timer 1 expired
Timer 2 stopped: false
Timer 2 stopped: true

View File

@@ -0,0 +1,18 @@
// ## Tickers
package main
import "time"
import "fmt"
func main() {
ticker := time.NewTicker(time.Millisecond * 500)
go func() {
for t := range ticker.C {
fmt.Println("Tick at", t)
}
}()
time.Sleep(time.Millisecond * 1500)
ticker.Stop()
fmt.Println("Ticker stopped")
}

View File

@@ -0,0 +1,5 @@
$ go run tickers.go
Tick at 2012-09-23 11:29:56.487625 -0700 PDT
Tick at 2012-09-23 11:29:56.988063 -0700 PDT
Tick at 2012-09-23 11:29:57.488076 -0700 PDT
Ticker stopped

View File

@@ -0,0 +1,28 @@
// ## Sorting
// The `sort` package implements sorting for builtins
// and user-defined types. We'll look at some of the
// sorts for builtins here.
package main
import "fmt"
import "sort"
func main() {
// Sort methods are specific to the builtin type.
// Sorting is in-place (doesn't return a new slice).
strs := []string{"c", "a", "b"}
sort.Strings(strs)
fmt.Println(strs)
// Sorting methods are named after the type.
ints := []int{7, 2, 4}
sort.Ints(ints)
fmt.Println(ints)
// Check if a slice is in sorted order.
s := sort.IntsAreSorted(ints)
fmt.Println(s)
}
// todo: general and convenience searching

View File

@@ -0,0 +1,5 @@
$ go run sorting.go
[a b c]
[2 4 7]
true
1

View File

@@ -0,0 +1,52 @@
// ## Sorting by Functions
package main
import (
"fmt"
"sort"
)
type Person struct {
Name string
Age int
}
type ByName []Person
func (this ByName) Len() int {
return len(this)
}
func (this ByName) Less(i, j int) bool {
return this[i].Name < this[j].Name
}
func (this ByName) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
type ByAge []Person
func (this ByAge) Len() int {
return len(this)
}
func (this ByAge) Less(i, j int) bool {
return this[i].Age < this[j].Age
}
func (this ByAge) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
func main() {
kids := []Person{
{"Jack", 10},
{"Jill", 9},
{"Bob", 12},
}
fmt.Println("Original:", kids)
sort.Sort(ByName(kids))
fmt.Println("ByName: ", kids)
sort.Sort(ByAge(kids))
fmt.Println("ByAge: ", kids)
}

View File

@@ -0,0 +1,4 @@
$ go run sorting-by-function.go
Original: [{Jack 10} {Jill 9} {Bob 12}]
ByName: [{Bob 12} {Jack 10} {Jill 9}]
ByAge: [{Jill 9} {Jack 10} {Bob 12}]

View File

@@ -0,0 +1,95 @@
// ## Collection Functions
package main
import "strings"
import "fmt"
func Index(elems []string, val string) int {
for i, v := range elems {
if v == val {
return i
}
}
return -1
}
func Include(elems []string, val string) bool {
return Index(elems, val) >= 0
}
func Any(elems []string, f func(string) bool) bool {
for _, v := range elems {
if f(v) {
return true
}
}
return false
}
func All(elems []string, f func(string) bool) bool {
for _, v := range elems {
if !f(v) {
return false
}
}
return true
}
func Filter(elems []string, f func(string) bool) []string {
filtered := []string{}
for _, v := range elems {
if f(v) {
filtered = append(filtered, v)
}
}
return filtered
}
func Map(elems []string, f func(string) string) []string {
mapped := make([]string, len(elems))
for i, v := range elems {
mapped[i] = f(v)
}
return mapped
}
func main() {
var elems = []string{"peach", "apple", "pear", "banana"}
fmt.Println(Index(elems, "pear"))
fmt.Println(Index(elems, "grape"))
fmt.Println()
fmt.Println(Include(elems, "pear"))
fmt.Println(Include(elems, "grape"))
fmt.Println()
fmt.Println(Any(elems, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
fmt.Println(Any(elems, func(v string) bool {
return strings.HasPrefix(v, "g")
}))
fmt.Println()
fmt.Println(All(elems, func(v string) bool {
return strings.Contains(v, "a")
}))
fmt.Println(All(elems, func(v string) bool {
return strings.Contains(v, "p")
}))
fmt.Println()
fmt.Println(Filter(elems, func(v string) bool {
return strings.Contains(v, "p")
}))
fmt.Println()
fmt.Println(Map(elems, func(s string) string {
return strings.ToUpper(s)
}))
fmt.Println()
}
// todo: generics

View File

@@ -0,0 +1,26 @@
// ## String Functions
package main
import "strings"
import "fm"
func p(o interface{}) {
fmt.Println(o)
}
func main() {
p("hello"[0])
p(strings.Contains("test", "es"))
p(strings.Count("test", "t"))
p(strings.HasPrefix("test", "te"))
p(strings.HasSuffix("test", "st"))
p(strings.Index("test", "e"))
p(strings.Join([]string{"a", "b"}, "-"))
p(strings.Repeat("a", 5))
p(strings.Replace("foo", "o", "0", -1))
p(strings.Replace("foo", "o", "0", 1))
p(strings.Split("a-b-c-d-e", "-"))
p(strings.ToLower("TEST"))
p(strings.ToUpper("test"))
}

View File

@@ -0,0 +1,22 @@
// ## String Formatting
package main
import "fmt"
type Point struct {
x, y int
}
func main() {
point := Point{1, 2}
fmt.Printf("default: %v\n", point)
fmt.Printf("default w/ vals: %+v\n", point)
fmt.Printf("go: %#v\n", point)
fmt.Printf("go type: %T\n", point)
fmt.Printf("boolean: %t\n", true)
}
// todo: the rest

View File

@@ -0,0 +1,6 @@
$ go run string-formatting.go
default: {1 2}
default w/ vals: {x:1 y:2}
go: main.Point{x:1, y:2}
go type: main.Point
boolean: true

20
src/046-regexs/regexs.go Normal file
View File

@@ -0,0 +1,20 @@
// Regexs
package main
import "regexp"
import "fmt"
func main() {
m1, _ := regexp.MatchString("p[a-z]+ch", "apple")
m2, _ := regexp.MatchString("p[a-z]+ch", "peach")
fmt.Println(m1)
fmt.Println(m2)
r1, _ := regexp.Compile("p[a-z]+ch")
fmt.Println(r1.MatchString("apple"))
fmt.Println(r1.MatchString("peach"))
}
// todo: more
// todo: gsub with regexp

5
src/046-regexs/regexs.sh Normal file
View File

@@ -0,0 +1,5 @@
$ go run regexs.go
false
true
false
true

12
src/047-bytes/bytes.go Normal file
View File

@@ -0,0 +1,12 @@
// ## Bytes
package main
import "fmt"
func main() {
arr := []byte("some bytes")
str := string([]byte{'a', ' ', 's', 't', 'r', 'i', 'n', 'g'})
fmt.Println(arr)
fmt.Println(str)
}

39
src/048-json/json.go Normal file
View File

@@ -0,0 +1,39 @@
// JSON
package main
import "encoding/json"
import "fmt"
func main() {
// data to bytes/string
bol, _ := json.Marshal(true)
fmt.Println(string(bol))
num, _ := json.Marshal(1)
fmt.Println(string(num))
str, _ := json.Marshal("gopher")
fmt.Println(string(str))
arr, _ := json.Marshal([]string{"apple", "peach", "pear"})
fmt.Println(string(arr))
hsh, _ := json.Marshal(map[string]int{"apple": 5, "lettuce": 7})
fmt.Println(string(hsh))
// string to data
byt := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
var dat map[string]interface{}
err := json.Unmarshal(byt, &dat)
if err != nil {
panic(err)
}
fmt.Println(dat)
name := dat["Name"].(string)
fmt.Println(name)
parents := dat["Parents"].([]interface{})
fmt.Println(parents)
}

21
src/049-time/time.go Normal file
View File

@@ -0,0 +1,21 @@
// ## Time
package main
import "time"
import "fmt"
func main() {
now := time.Now()
fmt.Println(now)
then := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
fmt.Println(then)
diff := now.Sub(then)
fmt.Println(diff)
}
// todo: extract parts
// todo: add duration
// todo: check before / after

4
src/049-time/time.sh Normal file
View File

@@ -0,0 +1,4 @@
$ go run time.go
2012-09-23 11:28:59.551605 -0700 PDT
2009-11-17 20:34:58.651387237 +0000 UTC
24981h54m0.900217763s

19
src/050-epochs/epochs.go Normal file
View File

@@ -0,0 +1,19 @@
// ## Epochs
package main
import "time"
func main() {
// Use `time.Now` with `Unix` or `UnixNane` to get
// elapsed time since the Unix epoch.
now := time.Now()
secs := now.Unix()
nanos := now.UnixNano()
// There is no `UnixMillis`.
millis := nanos / 1000000
println("Secs: ", secs)
println("Millis:", millis)
println("Nanos: ", nanos)
}

4
src/050-epochs/epochs.sh Normal file
View File

@@ -0,0 +1,4 @@
$ go run epochs.go
Secs: 1348240948
Millis: 1348240948517
Nanos: 1348240948517870000

View File

@@ -0,0 +1,12 @@
// ## Elapsed Time
package main
import "time"
import "fmt"
func main() {
start := time.Now()
time.Sleep(3 * time.Second)
fmt.Println(time.Since(start))
}

View File

@@ -0,0 +1,39 @@
// Random Numbers
package main
// The `math/rand` package provides psuedo-random
// numbers.
import "math/rand"
import "fmt"
func main() {
// For example, `rand.Intn` returns a random `int` n,
// `0 <= n < 100`.
fmt.Print(rand.Intn(100), ",")
fmt.Print(rand.Intn(100))
fmt.Println()
// `rand.Float64` returns a `float64` `f`,
// `0.0 <= f < 1.0`.
fmt.Println(rand.Float64())
// To make the psuedo-random generator deterministic,
// give it a well-known seed.
s1 := rand.NewSource(42)
r1 := rand.New(s1)
// Call the resulting `rand.Source` just like the
// functions on the `rand` package.
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
// If you seed a source with the same number, it
// produces the same sequence of random numbers.
s2 := rand.NewSource(42)
r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
}

View File

@@ -0,0 +1,5 @@
$ go run random-numbers.go
81,87
0.6645600532184904
5,87
5,87

View File

@@ -0,0 +1,30 @@
// ## Number Parsing
package main
// Package `strconv` provides the number parsing.
import "strconv"
import "fmt"
func main() {
// `64` tells how many bits of precision to parse.
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f)
// `0` means infer the base from the string.
// `64` requires that the result fit in 64 bits.
i, _ := strconv.ParseInt("123", 0, 64)
println(i)
// `ParseInt` will recognize hex-formatted numbers.
d, _ := strconv.ParseInt("0x1b3e", 0, 64)
println(d)
// `Atoi` is a convenienice function for `int` parsing.
k, _ := strconv.Atoi("456")
println(k)
// Parse functions return an error on bad input.
_, e := strconv.Atoi("wat")
fmt.Println(e)
}

View File

@@ -0,0 +1,6 @@
$ go run xx-number-parsing.go
1.234
123
6974
456
strconv.ParseInt: parsing "wat": invalid syntax

29
src/054-urls/urls.go Normal file
View File

@@ -0,0 +1,29 @@
// ## URLs
package main
import "fmt"
import "net/url"
import "strings"
func main() {
u, err := url.Parse("postgres://user:pass@host.com:5432/path?k=v#frag")
if err != nil {
panic(err)
}
fmt.Println(u.Scheme)
fmt.Println(u.User)
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
fmt.Println(u.Host)
split := strings.Split(u.Host, ":")
fmt.Println(split[0])
fmt.Println(split[1])
fmt.Println(u.Path)
fmt.Println(u.Fragment)
fmt.Println(u.RawQuery)
m, _ := url.ParseQuery(u.RawQuery)
fmt.Println(m)
fmt.Println(m["k"][0])
}

13
src/054-urls/urls.sh Normal file
View File

@@ -0,0 +1,13 @@
$ go run urls.go
postgres
user:pass
user
pass
host.com:5432
host.com
5432
/path
frag
k=v
map[k:[v]]
v

View File

@@ -0,0 +1,16 @@
// ## Reading files
package main
import "io/ioutil"
import "fmt"
func main() {
contents, err := ioutil.ReadFile("xx-file-read.go")
if err != nil {
return
}
fmt.Print(string(contents))
}
// todo: streaming reads

View File

@@ -0,0 +1,16 @@
// ## Writing Files
package main
import "os"
func main() {
file, err := os.Create("xx-file-write.txt")
if err != nil {
panic(err)
}
defer file.Close()
file.WriteString("contents\n")
}
// todo: streaming writes

View File

@@ -0,0 +1,53 @@
// ## Line Filters
// A line filter program reads input on stdin,
// processes it, and prints results to stdout.
// Here's an example line filter that writes
// a capitalized version of all text it reads.
package main
// Package `bufio` will help us read line-by-line.
import "bufio"
import "bytes"
import "os"
import "io"
// We'll need to add our own newlines between
// processed lines.
func main() {
newline := []byte("\n")
// The buffered reader gives us `ReadLine`.
in := bufio.NewReader(os.Stdin)
out := os.Stdout
// If successful, each `ReadLine` returns bytes and a
// boolean indicating if don't have the whole line yet.
for {
inBytes, pfx, err := in.ReadLine()
// The `EOF` error is expected when we reach the end
// of the input, so exit gracefully in that case.
// Otherwise there is a problem.
if err == io.EOF {
return
}
if err != nil {
panic(err)
}
// Write out the upercased bytes, checking for an error
// here as well.
outBytes := bytes.ToUpper(inBytes)
_, err = out.Write(outBytes)
if err != nil {
panic(err)
}
// Unless this read was for a prefix (not the full
// line), we need to add our own newline.
if !pfx {
out.Write(newline)
}
}
}

View File

@@ -0,0 +1,8 @@
# Make a file with a few lowercase lines.
$ echo 'hello' > lines
$ echo 'filter' >> lines
# Use the line filter to get uppercase lines.
$ cat lines | go run line-filters.go
HELLO
FILTER

View File

@@ -0,0 +1,25 @@
// ## Command Line Arguments
// Use `os.Args` to access command-line arguments and
// the name of the program.
package main
import "os"
import "fmt"
func main() {
// `os.Args` includes the program name as the first
// value.
argsWithProg := os.Args
argsWithoutProg := os.Args[1:]
// `Args` are a slice, you can get individual args
// with normal indexing.
arg := os.Args[3]
fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg)
fmt.Println(arg)
}
// todo: discuss building before here

View File

@@ -0,0 +1,9 @@
# Build a `command-line-args` binary so that we have
# the expected program name.
$ go build command-line-arguments
$ ./command-line-arguments a b c d
[command-line-arguments a b c d]
[a b c d]
c

View File

@@ -0,0 +1,21 @@
// ## Command Line Flags
package main
import "flag"
import "fmt"
func main() {
maxp := flag.Int("repeat", 3, "time to repeat args")
flag.Parse()
for i := 0; i < *maxp; i++ {
for _, arg := range flag.Args() {
fmt.Println(arg)
}
}
}
// todo: multiple flags
// todo: trailing args
// todo: arg escaping
// todo: help text and usage errors

View File

@@ -0,0 +1,26 @@
// ## Environment Variables
package main
// Use the `os` package to list, set, and get
// environment variables.
import "os"
import "strings"
import "fmt"
func main() {
// `os.Environ` returns a slice of strings in the form
// `KEY=value`. You can `strings.Split` them to get
// the key and value.
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
fmt.Println(pair[0])
}
fmt.Println()
// `Setenv` sets a given key, value pair.
// `Getenv` returns the value at key, or an empty
// string if the key isn't present.
os.Setenv("FOO", "bar")
fmt.Println(os.Getenv("FOO"))
}

View File

@@ -0,0 +1,6 @@
$ go run environment-variables.go
HOME
PATH
PWD
...
bar

View File

@@ -0,0 +1,19 @@
// ## Spawning Processes
package main
import "os/exec"
import "fmt"
func main() {
cmd := exec.Command("ls", "-a", "-l")
out, err := cmd.Output()
if err != nil {
panic(err)
}
fmt.Println("Files:")
fmt.Print(string(out))
}
// todo: full command lines with bash
// todo: piping in stdin

View File

@@ -0,0 +1,6 @@
$ go run spawning-processes.go
Files:
total 8
drwxr-xr-x 3 mmcgrana staff 102 Sep 23 11:35 .
drwxr-xr-x 101 mmcgrana staff 3434 Sep 23 11:25 ..
-rw-r--r--@ 1 mmcgrana staff 241 Sep 23 11:37 spawning-processes.go

View File

@@ -0,0 +1,20 @@
// ## Exec'ing Processes
package main
import "syscall"
import "os"
import "os/exec"
func main() {
binary, lookErr := exec.LookPath("ls")
if lookErr != nil {
panic(lookErr)
}
execErr := syscall.Exec(binary, []string{"-a", "-l", "-h"}, os.Environ())
if execErr != nil {
panic(execErr)
}
}
// todo: note lack of fork

View File

@@ -0,0 +1,27 @@
// ## Signals
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
c := make(chan os.Signal, 1)
d := make(chan bool, 1)
signal.Notify(c, syscall.SIGINT)
go func() {
sig := <-c
fmt.Println()
fmt.Println(sig)
d <- true
}()
fmt.Println("Awaiting signal")
<-d
}
// todo: sending signals?

View File

@@ -0,0 +1,4 @@
$ go run signals.go
Awaiting signal
^C
interrupt

16
src/065-exit/exit.go Normal file
View File

@@ -0,0 +1,16 @@
// Exit
package main
// Use `os.Exit` to immediatly exit with a given
// status.
import "os"
func main() {
// This `println` will never be reached because the
// exit is immediate.
defer println("!")
os.Exit(3)
}
// todo: discuss building before getting here

11
src/065-exit/exit.sh Normal file
View File

@@ -0,0 +1,11 @@
# If you run `exit.go` using `go run`, the exit
# will be picked up by `go` and printed.
$ go run exit.go
exit status 3
# By building and executing a binary you can see
# the status in the terminal.
$ go build exit.go
$ ./exit
$ echo $?
3

View File

@@ -0,0 +1,17 @@
// ## HTTP Client
package main
import "net/http"
import "io/ioutil"
import "fmt"
func main() {
resp, err := http.Get("http://127.0.0.1:5000/")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Print(string(body))
}

View File

@@ -0,0 +1,22 @@
// ## HTTPS Client
package main
import "net/http"
import "crypto/tls"
import "io/ioutil"
import "fmt"
func main() {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://127.0.0.1:5000/")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Print(string(body))
}

79
src/068-redis/redis.go Normal file
View File

@@ -0,0 +1,79 @@
// ## Redis
package main
import "github.com/fzzbt/radix/redis"
import "time"
import "fmt"
func main() {
// initialize
conf := redis.DefaultConfig()
client := redis.NewClient(conf)
fmt.Println(conf)
fmt.Println(client)
// set & get
setRep := client.Set("foo", "bar")
if setRep.Err != nil {
panic(setRep.Err)
}
fmt.Println(setRep)
getRep := client.Get("foo")
if getRep.Err != nil {
panic(getRep.Err)
}
getStr, _ := getRep.Str()
fmt.Println(getRep)
fmt.Println(getStr)
// varadic calls
client.Set("foo1", "bar1")
client.Set("foo2", "bar2")
client.Set("foo3", "bar3")
mgetRep := client.Mget("foo1", "foo2", "foo3")
fmt.Println(mgetRep)
// multi calls
mcallRep := client.MultiCall(func(mc *redis.MultiCall) {
mc.Set("k1", "v1")
mc.Get("k1")
})
if mcallRep.Err != nil {
panic(mcallRep.Err)
}
mcallVal, _ := mcallRep.Elems[1].Str()
fmt.Println(mcallVal)
// transactional calls
tranRep := client.Transaction(func(mc *redis.MultiCall) {
mc.Set("k2", "v2")
mc.Get("k2")
})
if tranRep.Err != nil {
panic(tranRep.Err)
}
tranStr, _ := tranRep.Elems[1].Str()
fmt.Println(tranStr)
// pubsub
msgHdlr := func(msg *redis.Message) {
fmt.Println(msg)
}
sub, subErr := client.Subscription(msgHdlr)
if subErr != nil {
panic(subErr)
}
defer sub.Close()
sub.Subscribe("chan1", "chan2")
sub.Psubscribe("chan*")
client.Publish("chan1", "foo")
sub.Unsubscribe("chan1")
client.Publish("chan2", "bar")
time.Sleep(time.Second)
}
// todo: connection pooling & concurrency?
// todo: reconnection?
// todo: errors?
// todo: redis_url

6
src/068-redis/redis.sh Normal file
View File

@@ -0,0 +1,6 @@
# Start a Redis server.
$ redis-server
# In another terminal, run the redis client:
$ go get github.com/fzzbt/radix/redis
$ go run redis.go

View File

@@ -0,0 +1,70 @@
// ## Postgres
package main
import _ "github.com/bmizerany/pq"
import "database/sql"
import "time"
import "fmt"
func main() {
db, openErr := sql.Open("postgres", "dbname=gobyexample sslmode=disable")
if openErr != nil {
panic(openErr)
}
defer db.Close()
fmt.Println(db)
createRep, createErr := db.Exec("CREATE TABLE items (a int, b float, c boolean, d text, e timestamp with time zone)")
if createErr != nil {
panic(createErr)
}
fmt.Println(createRep)
insertRep, insertErr := db.Exec("INSERT INTO items VALUES (1, 2.0, false, 'string', '2000-01-01T01:02:03Z')")
if insertErr != nil {
panic(insertErr)
}
fmt.Println(insertRep)
t1, _ := time.Parse(time.RFC3339, "2000-04-08T03:02:01Z")
t2, _ := time.Parse(time.RFC3339, "2007-03-02T10:15:45Z")
minsertRep, minsertErr := db.Exec("Insert INTO items VALUES ($1, $2, $3, $4, $5), ($6, $7, $8, $9, $10)",
3, 7.0, true, "more", t1,
5, 1.0, false, "less", t2)
if minsertErr != nil {
panic(minsertErr)
}
num, _ := minsertRep.RowsAffected()
fmt.Println(num)
rows, selectErr := db.Query("SELECT * FROM items")
if selectErr != nil {
panic(selectErr)
}
defer rows.Close()
for rows.Next() {
var r1 int
var r2 float64
var r3 bool
var r4 string
var r5 time.Time
rows.Scan(&r1, &r2, &r3, &r4, &r5)
fmt.Println(r1, r2, r3, r4, r5)
}
rowsErr := rows.Err()
if rowsErr != nil {
panic(rowsErr)
}
dropRep, dropErr := db.Exec("DROP TABLE items")
if dropErr != nil {
panic(dropErr)
}
fmt.Println(dropRep)
}
// todo: connection pooling & concurrency
// todo: re-connection
// todo: errors
// todo: database_url

View File

@@ -0,0 +1,10 @@
# First, be sure that you've installed Postgres
# and have a server running locally at port 5432.
# Then create an example database.
$ createdb gobyexample
# Now install the dependencies for the postgres
# example and try running it.
$ go get github.com/bmizerany/pq
$ go run postgres.go

View File

@@ -0,0 +1,30 @@
// ## Sending Email
package main
import "net/smtp"
func main() {
auth := smtp.PlainAuth(
"",
"mark@heroku.com",
"xxx",
"smtp.gmail.com",
)
err := smtp.SendMail(
"smtp.gmail.com:25",
auth,
"mark+sent@heroku.com",
[]string{"mark@heroku.com"},
[]byte("nThe body."),
)
if err != nil {
panic(err)
}
}
// todo: missing subject, cc, bcc
// todo: attachements
// todo: plain/multi-type emails
// todo: https://github.com/mtoader/google-go-lang-idea-plugin/issues/112

View File

@@ -0,0 +1,15 @@
// ## Hello Web
package main
import "net/http"
func hello(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "text/plain")
res.Write([]byte("Hello web\n"))
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":5000", nil)
}

View File

@@ -0,0 +1,21 @@
// ## Responses
package main
import "net/http"
import "fmt"
func hello(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "text/plain")
if req.URL.Path == "/protected" {
res.WriteHeader(401)
fmt.Fprintln(res, "Not allowed")
} else {
fmt.Fprintln(res, "Hello")
}
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":5000", nil)
}

Some files were not shown because too many files have changed in this diff Show More