Go语言官网Example
数组
package main import "fmt" func main() { var a [5]int fmt.Println("emp:", a) a[4] = 100 fmt.Println("set:", a) fmt.Println("get:", a[4]) fmt.Println("len:", len(a)) b := [5]int{1, 2, 3, 4, 5} fmt.Println("dcl:", b) var twoD [2][3]int for i := 0; i < 2; i++ { for j := 0; j < 3; j++ { twoD[i][j] = i + j } } fmt.Println("2d: ", twoD) } /* emp: [0 0 0 0 0] set: [0 0 0 0 100] get: 100 len: 5 dcl: [1 2 3 4 5] 2d: [[0 1 2] [1 2 3]] */
切片
package main import "fmt" func main() { s := make([]string, 3) fmt.Println("emp:", s) s[0] = "a" s[1] = "b" s[2] = "c" fmt.Println("set:", s) fmt.Println("get:", s[2]) fmt.Println("len:", len(s)) s = append(s, "d") s = append(s, "e", "f") fmt.Println("apd:", s) c := make([]string, len(s)) copy(c, s) fmt.Println("cpy:", c) l := s[2:5] fmt.Println("sl1:", l) l = s[:5] fmt.Println("sl2:", l) l = s[2:] fmt.Println("sl3:", l) t := []string{"g", "h", "i"} fmt.Println("dcl:", t) twoD := make([][]int, 3) for i := 0; i < 3; i++ { innerLen := i + 1 twoD[i] = make([]int, innerLen) for j := 0; j < innerLen; j++ { twoD[i][j] = i + j } } fmt.Println("2d: ", twoD) } /* emp: [ ] set: [a b c] get: c len: 3 apd: [a b c d e f] cpy: [a b c d e f] sl1: [c d e] sl2: [a b c d e] sl3: [c d e f] dcl: [g h i] 2d: [[0] [1 2] [2 3 4]]*/
字典
package main import "fmt" func main() { m := make(map[string]int) m["k1"] = 7 m["k2"] = 13 fmt.Println("map:", m) v1 := m["k1"] fmt.Println("v1: ", v1) fmt.Println("len:", len(m)) delete(m, "k2") fmt.Println("map:", m) _, prs := m["k2"] fmt.Println("prs:", prs) n := map[string]int{"foo": 1, "bar": 2} fmt.Println("map:", n) } /* map: map[k1:7 k2:13] v1: 7 len: 2 map: map[k1:7] prs: false map: map[bar:2 foo:1]*/
遍历
package main import "fmt" func main() { nums := []int{2, 3, 4} sum := 0 for _, num := range nums { sum += num } fmt.Println("sum:", sum) for i, num := range nums { if num == 3 { fmt.Println("index:", i) } } kvs := map[string]string{"a": "apple", "b": "banana"} for k, v := range kvs { fmt.Printf("%s -> %s\n", k, v) } for k := range kvs { fmt.Println("key:", k) } for i, c := range "go" { fmt.Println(i, c) } } /* sum: 9 index: 1 a -> apple b -> banana key: a key: b 0 103 1 111*/
闭包
package main import "fmt" func intSeq() func() int { i := 0 return func() int { i++ return i } } func main() { nextInt := intSeq() fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) newInts := intSeq() fmt.Println(newInts()) } //1 2 3 1
递归
package main import "fmt" func fact(n int) int { if n == 0 { return 1 } return n * fact(n-1) } func main() { fmt.Println(fact(7)) } //5040
结构体
package main import "fmt" type person struct { name string age int } func newPerson(name string) *person { p := person{name: name} p.age = 42 return &p } func main() { fmt.Println(person{"Bob", 20}) fmt.Println(person{name: "Alice", age: 30}) fmt.Println(person{name: "Fred"}) fmt.Println(&person{name: "Ann", age: 40}) fmt.Println(newPerson("Jon")) s := person{name: "Sean", age: 50} fmt.Println(s.name) sp := &s fmt.Println(sp.age) sp.age = 51 fmt.Println(sp.age) } /*{Bob 20} {Alice 30} {Fred 0} &{Ann 40} &{Jon 42} Sean 50 51*/
结构体函数
package main import "fmt" type rect struct { width, height int } func (r *rect) area() int { return r.width * r.height } func (r rect) perim() int { return 2*r.width + 2*r.height } func main() { r := rect{width: 10, height: 5} fmt.Println("area: ", r.area()) fmt.Println("perim:", r.perim()) rp := &r fmt.Println("area: ", rp.area()) fmt.Println("perim:", rp.perim()) } /*area: 50 perim: 30 area: 50 perim: 30*/
接口
package main import ( "fmt" "math" ) type geometry interface { area() float64 perim() float64 } type rect struct { width, height float64 } type circle struct { radius float64 } func (r rect) area() float64 { return r.width * r.height } func (r rect) perim() float64 { return 2*r.width + 2*r.height } func (c circle) area() float64 { return math.Pi * c.radius * c.radius } func (c circle) perim() float64 { return 2 * math.Pi * c.radius } func measure(g geometry) { fmt.Println(g) fmt.Println(g.area()) fmt.Println(g.perim()) } func main() { r := rect{width: 3, height: 4} c := circle{radius: 5} measure(r) measure(c) } /* {3 4} 12 14 {5} 78.53981633974483 31.41592653589793*/
异常处理
package main import ( "errors" "fmt" ) func f1(arg int) (int, error) { if arg == 42 { return -1, errors.New("can‘t work with 42") } return arg + 3, nil } type argError struct { arg int prob string } func (e *argError) Error() string { return fmt.Sprintf("%d - %s", e.arg, e.prob) } func f2(arg int) (int, error) { if arg == 42 { return -1, &argError{arg, "can‘t work with it"} } return arg + 3, nil } func main() { for _, i := range []int{7, 42} { if r, e := f1(i); e != nil { fmt.Println("f1 failed:", e) } else { fmt.Println("f1 worked:", r) } } for _, i := range []int{7, 42} { if r, e := f2(i); e != nil { fmt.Println("f2 failed:", e) } else { fmt.Println("f2 worked:", r) } } _, e := f2(42) if ae, ok := e.(*argError); ok { fmt.Println(ae.arg) fmt.Println(ae.prob) } } /*f1 worked: 10 f1 failed: can‘t work with 42 f2 worked: 10 f2 failed: 42 - can‘t work with it 42 can‘t work with it*/
Channel同步
go语言提倡:非共享内存来同步数据,而是共享通信来同步数据
package main import ( "fmt" "time" ) func worker(done chan bool) { fmt.Print("working...") time.Sleep(time.Second) fmt.Println("done") done <- true } func main() { done := make(chan bool, 1) go worker(done) <-done } // working ... done
Select
Go’s select lets you wait on multiple channel operations. Combining goroutines and channels with select is a powerful feature of Go.
package main import ( "fmt" "time" ) func main() { c1 := make(chan string) c2 := make(chan string) go func() { time.Sleep(1 * time.Second) c1 <- "one" }() go func() { time.Sleep(2 * time.Second) c2 <- "two" }() for i := 0; i < 2; i++ { select { case msg1 := <-c1: fmt.Println("received", msg1) case msg2 := <-c2: fmt.Println("received", msg2) } } } /*received one received two real 0m2.245*/
超时
package main import ( "fmt" "time" ) func main() { c1 := make(chan string, 1) go func() { time.Sleep(2 * time.Second) c1 <- "result 1" }() select { case res := <-c1: fmt.Println(res) case <-time.After(1 * time.Second): fmt.Println("timeout 1") } c2 := make(chan string, 1) go func() { time.Sleep(2 * time.Second) c2 <- "result 2" }() select { case res := <-c2: fmt.Println(res) case <-time.After(3 * time.Second): fmt.Println("timeout 2") } } /*timeout 1 result 2*/
Channel的关闭和消费生产者模型
package main import "fmt" func main() { jobs := make(chan int, 5) done := make(chan bool) go func() { for { j, more := <-jobs if more { fmt.Println("received job", j) } else { fmt.Println("received all jobs") done <- true return } } }() for j := 1; j <= 3; j++ { jobs <- j fmt.Println("sent job", j) } close(jobs) fmt.Println("sent all jobs") <-done } /* sent job 1 received job 1 sent job 2 received job 2 sent job 3 received job 3 sent all jobs received all jobs*/
Channel的遍历
package main import "fmt" func main() { queue := make(chan string, 2) queue <- "one" queue <- "two" close(queue) for elem := range queue { fmt.Println(elem) } } /* one two*/
Timer
package main import ( "fmt" "time" ) func main() { timer1 := time.NewTimer(time.Second * 2) t1 := time.Now() fmt.Printf("t1:%v\n", t1) t2 := <-timer1.C fmt.Printf("t2:%v\n", t2) //如果只是想单纯的等待的话,可以使用 time.Sleep 来实现 timer2 := time.NewTimer(time.Second * 2) <-timer2.C fmt.Println("2s后") time.Sleep(time.Second * 2) fmt.Println("再一次2s后") <-time.After(time.Second * 2) //time.After函数的返回值是chan Time fmt.Println("再再一次2s后") timer3 := time.NewTimer(time.Second) go func() { <-timer3.C fmt.Println("Timer 3 expired") }() stop := timer3.Stop() //停止定时器 //阻止timer事件发生,当该函数执行后,timer计时器停止,相应的事件不再执行 if stop { fmt.Println("Timer 3 stopped") } fmt.Println("before") timer4 := time.NewTimer(time.Second * 5) //原来设置5s timer4.Reset(time.Second * 1) //重新设置时间,即修改NewTimer的时间 <-timer4.C fmt.Println("after") } /* t1:2020-04-14 09:18:47.4708004 +0800 CST m=+0.001994001 t2:2020-04-14 09:18:49.4710156 +0800 CST m=+2.002209201 2s后 再一次2s后 再再一次2s后 Timer 3 stopped before after*/
Timer.tickers
package main import ( "fmt" "time" ) func main() { ticker := time.NewTicker(500 * time.Millisecond) done := make(chan bool) go func() { for { select { case <-done: return case t := <-ticker.C: fmt.Println("Tick at", t) } } }() time.Sleep(1600 * time.Millisecond) ticker.Stop() done <- true fmt.Println("Ticker stopped") } /* 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*/
work pool
package main import ( "fmt" "time" ) func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Println("worker", id, "started job", j) time.Sleep(time.Second) fmt.Println("worker", id, "finished job", j) results <- j * 2 } } func main() { const numJobs = 5 jobs := make(chan int, numJobs) results := make(chan int, numJobs) for w := 1; w <= 3; w++ { go worker(w, jobs, results) } for j := 1; j <= numJobs; j++ { jobs <- j } close(jobs) for a := 1; a <= numJobs; a++ { <-results } } /*worker 1 started job 1 worker 2 started job 2 worker 3 started job 3 worker 1 finished job 1 worker 1 started job 4 worker 2 finished job 2 worker 2 started job 5 worker 3 finished job 3 worker 1 finished job 4 worker 2 finished job 5*/
WaitGroup
This is the function we’ll run in every goroutine. Note that a WaitGroup must be passed to functions by pointer.
package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go worker(i, &wg) } wg.Wait() } /*Worker 5 starting Worker 3 starting Worker 4 starting Worker 1 starting Worker 2 starting Worker 4 done Worker 1 done Worker 2 done Worker 5 done Worker 3 done*/
Rate Limiting
Rate limiting is an important mechanism for controlling resource utilization and maintaining quality of service. Go elegantly supports rate limiting with goroutines, channels, and tickers.
package main import ( "fmt" "time" ) func main() { requests := make(chan int, 5) for i := 1; i <= 5; i++ { requests <- i } close(requests) limiter := time.Tick(200 * time.Millisecond) for req := range requests { <-limiter fmt.Println("request", req, time.Now()) } burstyLimiter := make(chan time.Time, 3) for i := 0; i < 3; i++ { burstyLimiter <- time.Now() } go func() { for t := range time.Tick(200 * time.Millisecond) { burstyLimiter <- t } }() burstyRequests := make(chan int, 5) for i := 1; i <= 5; i++ { burstyRequests <- i } close(burstyRequests) for req := range burstyRequests { <-burstyLimiter fmt.Println("request", req, time.Now()) } } /*request 1 2012-10-19 00:38:18.687438 +0000 UTC request 2 2012-10-19 00:38:18.887471 +0000 UTC request 3 2012-10-19 00:38:19.087238 +0000 UTC request 4 2012-10-19 00:38:19.287338 +0000 UTC request 5 2012-10-19 00:38:19.487331 +0000 UTC request 1 2012-10-19 00:38:20.487578 +0000 UTC request 2 2012-10-19 00:38:20.487645 +0000 UTC request 3 2012-10-19 00:38:20.487676 +0000 UTC request 4 2012-10-19 00:38:20.687483 +0000 UTC request 5 2012-10-19 00:38:20.887542 +0000 UTC*/
Atomic Counters
package main import ( "fmt" "sync" "sync/atomic" ) func main() { var ops uint64 var wg sync.WaitGroup for i := 0; i < 50; i++ { wg.Add(1) go func() { for c := 0; c < 1000; c++ { atomic.AddUint64(&ops, 1) } wg.Done() }() } wg.Wait() fmt.Println("ops:", ops) } /* ops: 50000*/
Mutexs
In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple goroutines.
package main import ( "fmt" "math/rand" "sync" "sync/atomic" "time" ) func main() { var state = make(map[int]int) var mutex = &sync.Mutex{} var readOps uint64 var writeOps uint64 for r := 0; r < 100; r++ { go func() { total := 0 for { key := rand.Intn(5) mutex.Lock() total += state[key] mutex.Unlock() atomic.AddUint64(&readOps, 1) time.Sleep(time.Millisecond) } }() } for w := 0; w < 10; w++ { go func() { for { key := rand.Intn(5) val := rand.Intn(100) mutex.Lock() state[key] = val mutex.Unlock() atomic.AddUint64(&writeOps, 1) time.Sleep(time.Millisecond) } }() } time.Sleep(time.Second) readOpsFinal := atomic.LoadUint64(&readOps) fmt.Println("readOps:", readOpsFinal) writeOpsFinal := atomic.LoadUint64(&writeOps) fmt.Println("writeOps:", writeOpsFinal) mutex.Lock() fmt.Println("state:", state) mutex.Unlock() } /* readOps: 83285 writeOps: 8320 state: map[1:97 4:53 0:33 2:15 3:2]*/
Stateful Goroutines 有状态的Goroutines
package main import ( "fmt" "math/rand" "sync/atomic" "time" ) type readOp struct { key int resp chan int } type writeOp struct { key int val int resp chan bool } func main() { var readOps uint64 var writeOps uint64 reads := make(chan readOp) writes := make(chan writeOp) go func() { var state = make(map[int]int) for { select { case read := <-reads: read.resp <- state[read.key] case write := <-writes: state[write.key] = write.val write.resp <- true } } }() for r := 0; r < 100; r++ { go func() { for { read := readOp{ key: rand.Intn(5), resp: make(chan int)} reads <- read <-read.resp atomic.AddUint64(&readOps, 1) time.Sleep(time.Millisecond) } }() } for w := 0; w < 10; w++ { go func() { for { write := writeOp{ key: rand.Intn(5), val: rand.Intn(100), resp: make(chan bool)} writes <- write <-write.resp atomic.AddUint64(&writeOps, 1) time.Sleep(time.Millisecond) } }() } time.Sleep(time.Second) readOpsFinal := atomic.LoadUint64(&readOps) fmt.Println("readOps:", readOpsFinal) writeOpsFinal := atomic.LoadUint64(&writeOps) fmt.Println("writeOps:", writeOpsFinal) } /* readOps: 71708 writeOps: 7177*/
Collection Function
package main import ( "fmt" "strings" ) func Index(vs []string, t string) int { for i, v := range vs { if v == t { return i } } return -1 } func Include(vs []string, t string) bool { return Index(vs, t) >= 0 } func Any(vs []string, f func(string) bool) bool { for _, v := range vs { if f(v) { return true } } return false } func All(vs []string, f func(string) bool) bool { for _, v := range vs { if !f(v) { return false } } return true } func Filter(vs []string, f func(string) bool) []string { vsf := make([]string, 0) for _, v := range vs { if f(v) { vsf = append(vsf, v) } } return vsf } func Map(vs []string, f func(string) string) []string { vsm := make([]string, len(vs)) for i, v := range vs { vsm[i] = f(v) } return vsm } func main() { var strs = []string{"peach", "apple", "pear", "plum"} fmt.Println(Index(strs, "pear")) fmt.Println(Include(strs, "grape")) fmt.Println(Any(strs, func(v string) bool { return strings.HasPrefix(v, "p") })) fmt.Println(All(strs, func(v string) bool { return strings.HasPrefix(v, "p") })) fmt.Println(Filter(strs, func(v string) bool { return strings.Contains(v, "e") })) fmt.Println(Map(strs, strings.ToUpper)) } /* 2 false true false [peach apple pear] [PEACH APPLE PEAR PLUM]*/
String Function
package main import ( "fmt" s "strings" ) var p = fmt.Println func main() { p("Contains: ", s.Contains("test", "es")) p("Count: ", s.Count("test", "t")) p("HasPrefix: ", s.HasPrefix("test", "te")) p("HasSuffix: ", s.HasSuffix("test", "st")) p("Index: ", s.Index("test", "e")) p("Join: ", s.Join([]string{"a", "b"}, "-")) p("Repeat: ", s.Repeat("a", 5)) p("Replace: ", s.Replace("foo", "o", "0", -1)) p("Replace: ", s.Replace("foo", "o", "0", 1)) p("Split: ", s.Split("a-b-c-d-e", "-")) p("ToLower: ", s.ToLower("TEST")) p("ToUpper: ", s.ToUpper("test")) p() p("Len: ", len("hello")) p("Char:", "hello"[1]) }package main import ( "fmt" s "strings" ) var p = fmt.Println func main() { p("Contains: ", s.Contains("test", "es")) p("Count: ", s.Count("test", "t")) p("HasPrefix: ", s.HasPrefix("test", "te")) p("HasSuffix: ", s.HasSuffix("test", "st")) p("Index: ", s.Index("test", "e")) p("Join: ", s.Join([]string{"a", "b"}, "-")) p("Repeat: ", s.Repeat("a", 5)) p("Replace: ", s.Replace("foo", "o", "0", -1)) p("Replace: ", s.Replace("foo", "o", "0", 1)) p("Split: ", s.Split("a-b-c-d-e", "-")) p("ToLower: ", s.ToLower("TEST")) p("ToUpper: ", s.ToUpper("test")) p() p("Len: ", len("hello")) p("Char:", "hello"[1]) } /* Contains: true Count: 2 HasPrefix: true HasSuffix: true Index: 1 Join: a-b Repeat: aaaaa Replace: f00 Replace: f0o Split: [a b c d e] ToLower: test ToUpper: TEST Len: 5 Char: 101*/
String formatting
package main import ( "fmt" "os" ) type point struct { x, y int } func main() { p := point{1, 2} fmt.Printf("%v\n", p) fmt.Printf("%+v\n", p) fmt.Printf("%#v\n", p) fmt.Printf("%T\n", p) fmt.Printf("%t\n", true) fmt.Printf("%d\n", 123) fmt.Printf("%b\n", 14) fmt.Printf("%c\n", 33) fmt.Printf("%x\n", 456) fmt.Printf("%f\n", 78.9) fmt.Printf("%e\n", 123400000.0) fmt.Printf("%E\n", 123400000.0) fmt.Printf("%s\n", "\"string\"") fmt.Printf("%q\n", "\"string\"") fmt.Printf("%x\n", "hex this") fmt.Printf("%p\n", &p) fmt.Printf("|%6d|%6d|\n", 12, 345) fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45) fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45) fmt.Printf("|%6s|%6s|\n", "foo", "b") fmt.Printf("|%-6s|%-6s|\n", "foo", "b") s := fmt.Sprintf("a %s", "string") fmt.Println(s) fmt.Fprintf(os.Stderr, "an %s\n", "error") } /* {1 2} {x:1 y:2} main.point{x:1, y:2} main.point true 123 1110 ! 1c8 78.900000 1.234000e+08 1.234000E+08 "string" "\"string\"" 6865782074686973 0x42135100 | 12| 345| | 1.20| 3.45| |1.20 |3.45 | | foo| b| |foo |b | a string an error*/
Regular Expressions
package main import ( "bytes" "fmt" "regexp" ) func main() { match, _ := regexp.MatchString("p([a-z]+)ch", "peach") fmt.Println(match) r, _ := regexp.Compile("p([a-z]+)ch") fmt.Println(r.MatchString("peach")) fmt.Println(r.FindString("peach punch")) fmt.Println(r.FindStringIndex("peach punch")) fmt.Println(r.FindStringSubmatch("peach punch")) fmt.Println(r.FindStringSubmatchIndex("peach punch")) fmt.Println(r.FindAllString("peach punch pinch", -1)) fmt.Println(r.FindAllStringSubmatchIndex( "peach punch pinch", -1)) fmt.Println(r.FindAllString("peach punch pinch", 2)) fmt.Println(r.Match([]byte("peach"))) r = regexp.MustCompile("p([a-z]+)ch") fmt.Println(r) fmt.Println(r.ReplaceAllString("a peach", "<fruit>")) in := []byte("a peach") out := r.ReplaceAllFunc(in, bytes.ToUpper) fmt.Println(string(out)) } /* true true peach [0 5] [peach ea] [0 5 1 3] [peach punch pinch] [[0 5 1 3] [6 11 7 9] [12 17 13 15]] [peach punch] true p([a-z]+)ch a <fruit> a PEACH*/
Json
package main import ( "encoding/json" "fmt" "os" ) type response1 struct { Page int Fruits []string } type response2 struct { Page int `json:"page"` Fruits []string `json:"fruits"` } func main() { bolB, _ := json.Marshal(true) fmt.Println(string(bolB)) intB, _ := json.Marshal(1) fmt.Println(string(intB)) fltB, _ := json.Marshal(2.34) fmt.Println(string(fltB)) strB, _ := json.Marshal("gopher") fmt.Println(string(strB)) slcD := []string{"apple", "peach", "pear"} slcB, _ := json.Marshal(slcD) fmt.Println(string(slcB)) mapD := map[string]int{"apple": 5, "lettuce": 7} mapB, _ := json.Marshal(mapD) fmt.Println(string(mapB)) res1D := &response1{ Page: 1, Fruits: []string{"apple", "peach", "pear"}} res1B, _ := json.Marshal(res1D) fmt.Println(string(res1B)) res2D := &response2{ Page: 1, Fruits: []string{"apple", "peach", "pear"}} res2B, _ := json.Marshal(res2D) fmt.Println(string(res2B)) byt := []byte(`{"num":6.13,"strs":["a","b"]}`) var dat map[string]interface{} if err := json.Unmarshal(byt, &dat); err != nil { panic(err) } fmt.Println(dat) num := dat["num"].(float64) fmt.Println(num) strs := dat["strs"].([]interface{}) str1 := strs[0].(string) fmt.Println(str1) str := `{"page": 1, "fruits": ["apple", "peach"]}` res := response2{} json.Unmarshal([]byte(str), &res) fmt.Println(res) fmt.Println(res.Fruits[0]) enc := json.NewEncoder(os.Stdout) d := map[string]int{"apple": 5, "lettuce": 7} enc.Encode(d) } /* true 1 2.34 "gopher" ["apple","peach","pear"] {"apple":5,"lettuce":7} {"Page":1,"Fruits":["apple","peach","pear"]} {"page":1,"fruits":["apple","peach","pear"]} map[num:6.13 strs:[a b]] 6.13 a {1 [apple peach]} apple {"apple":5,"lettuce":7}*/
Time
package main import ( "fmt" "time" ) func main() { p := fmt.Println now := time.Now() p(now) then := time.Date( 2009, 11, 17, 20, 34, 58, 651387237, time.UTC) p(then) p(then.Year()) p(then.Month()) p(then.Day()) p(then.Hour()) p(then.Minute()) p(then.Second()) p(then.Nanosecond()) p(then.Location()) p(then.Weekday()) p(then.Before(now)) p(then.After(now)) p(then.Equal(now)) diff := now.Sub(then) p(diff) p(diff.Hours()) p(diff.Minutes()) p(diff.Seconds()) p(diff.Nanoseconds()) p(then.Add(diff)) p(then.Add(-diff)) } /* 2012-10-31 15:50:13.793654 +0000 UTC 2009-11-17 20:34:58.651387237 +0000 UTC 2009 November 17 20 34 58 651387237 UTC Tuesday true false false 25891h15m15.142266763s 25891.25420618521 1.5534752523711128e+06 9.320851514226677e+07 93208515142266763 2012-10-31 15:50:13.793654 +0000 UTC 2006-12-05 01:19:43.509120474 +0000 UTC*/
Time Formatting
package main import ( "fmt" "time" ) func main() { p := fmt.Println t := time.Now() p(t.Format(time.RFC3339)) t1, e := time.Parse( time.RFC3339, "2012-11-01T22:08:41+00:00") p(t1) p(t.Format("3:04PM")) p(t.Format("Mon Jan _2 15:04:05 2006")) p(t.Format("2006-01-02T15:04:05.999999-07:00")) form := "3 04 PM" t2, e := time.Parse(form, "8 41 PM") p(t2) fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) ansic := "Mon Jan _2 15:04:05 2006" _, e = time.Parse(ansic, "8:41PM") p(e) } /* 2014-04-15T18:00:15-07:00 2012-11-01 22:08:41 +0000 +0000 6:00PM Tue Apr 15 18:00:15 2014 2014-04-15T18:00:15.161182-07:00 0000-01-01 20:41:00 +0000 UTC 2014-04-15T18:00:15-00:00 parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": ...*/
random Numbers
package main import ( "fmt" "math/rand" "time" ) func main() { fmt.Print(rand.Intn(100), ",") fmt.Print(rand.Intn(100)) fmt.Println() fmt.Println(rand.Float64()) fmt.Print((rand.Float64()*5)+5, ",") fmt.Print((rand.Float64() * 5) + 5) fmt.Println() s1 := rand.NewSource(time.Now().UnixNano()) r1 := rand.New(s1) fmt.Print(r1.Intn(100), ",") fmt.Print(r1.Intn(100)) fmt.Println() s2 := rand.NewSource(42) r2 := rand.New(s2) fmt.Print(r2.Intn(100), ",") fmt.Print(r2.Intn(100)) fmt.Println() s3 := rand.NewSource(42) r3 := rand.New(s3) fmt.Print(r3.Intn(100), ",") fmt.Print(r3.Intn(100)) } /* 81,87 0.6645600532184904 7.123187485356329,8.434115364335547 0,28 5,87 5,87*/
Reading File
package main import ( "bufio" "fmt" "io" "io/ioutil" "os" ) func check(e error) { if e != nil { panic(e) } } func main() { dat, err := ioutil.ReadFile("/tmp/dat") check(err) fmt.Print(string(dat)) f, err := os.Open("/tmp/dat") check(err) b1 := make([]byte, 5) n1, err := f.Read(b1) check(err) fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1])) o2, err := f.Seek(6, 0) check(err) b2 := make([]byte, 2) n2, err := f.Read(b2) check(err) fmt.Printf("%d bytes @ %d: ", n2, o2) fmt.Printf("%v\n", string(b2[:n2])) o3, err := f.Seek(6, 0) check(err) b3 := make([]byte, 2) n3, err := io.ReadAtLeast(f, b3, 2) check(err) fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) _, err = f.Seek(0, 0) check(err) r4 := bufio.NewReader(f) b4, err := r4.Peek(5) check(err) fmt.Printf("5 bytes: %s\n", string(b4)) f.Close() } /* hello go 5 bytes: hello 2 bytes @ 6: go 2 bytes @ 6: go 5 bytes: hello*/
Write File
package main import ( "bufio" "fmt" "io/ioutil" "os" ) func check(e error) { if e != nil { panic(e) } } func main() { d1 := []byte("hello\ngo\n") err := ioutil.WriteFile("/tmp/dat1", d1, 0644) check(err) f, err := os.Create("/tmp/dat2") check(err) defer f.Close() d2 := []byte{115, 111, 109, 101, 10} n2, err := f.Write(d2) check(err) fmt.Printf("wrote %d bytes\n", n2) n3, err := f.WriteString("writes\n") check(err) fmt.Printf("wrote %d bytes\n", n3) f.Sync() w := bufio.NewWriter(f) n4, err := w.WriteString("buffered\n") check(err) fmt.Printf("wrote %d bytes\n", n4) w.Flush() } /* $ cat /tmp/dat1 hello go $ cat /tmp/dat2 some writes buffered*/
Line Filters
package main import ( "bufio" "fmt" "os" "strings" ) func main() { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { ucl := strings.ToUpper(scanner.Text()) fmt.Println(ucl) } if err := scanner.Err(); err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) } } /* $ echo ‘hello‘ > /tmp/lines $ echo ‘filter‘ >> /tmp/lines cat /tmp/lines | go run line-filters.go HELLO FILTER*/
File Path
package main import ( "fmt" "path/filepath" "strings" ) func main() { p := filepath.Join("dir1", "dir2", "filename") fmt.Println("p:", p) fmt.Println(filepath.Join("dir1//", "filename")) fmt.Println(filepath.Join("dir1/../dir1", "filename")) fmt.Println("Dir(p):", filepath.Dir(p)) fmt.Println("Base(p):", filepath.Base(p)) fmt.Println(filepath.IsAbs("dir/file")) fmt.Println(filepath.IsAbs("/dir/file")) filename := "config.json" ext := filepath.Ext(filename) fmt.Println(ext) fmt.Println(strings.TrimSuffix(filename, ext)) rel, err := filepath.Rel("a/b", "a/b/t/file") if err != nil { panic(err) } fmt.Println(rel) rel, err = filepath.Rel("a/b", "a/c/t/file") if err != nil { panic(err) } fmt.Println(rel) } /* p: dir1/dir2/filename dir1/filename dir1/filename Dir(p): dir1/dir2 Base(p): filename false true .json config t/file ../c/t/file*/
Context
In the previous example we looked at setting up a simple HTTP server. HTTP servers are useful for demonstrating the usage of context.Context
for controlling cancellation. A Context
carries deadlines, cancellation signals, and other request-scoped values across API boundaries and goroutines.
package main import ( "fmt" "net/http" "time" ) func hello(w http.ResponseWriter, req *http.Request) { ctx := req.Context() fmt.Println("server: hello handler started") defer fmt.Println("server: hello handler ended") select { case <-time.After(10 * time.Second): fmt.Fprintf(w, "hello\n") case <-ctx.Done(): err := ctx.Err() fmt.Println("server:", err) internalError := http.StatusInternalServerError http.Error(w, err.Error(), internalError) } } func main() { http.HandleFunc("/hello", hello) http.ListenAndServe(":8090", nil) } /* curl localhost:8090/hello server: hello handler started ^C server: context canceled server: hello handler ended*/