diff --git a/array.go b/array.go new file mode 100644 index 0000000..0d19256 --- /dev/null +++ b/array.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +func main() { + var a [6]int + fmt.Println("empty:", a) + + a[3] = 100 + fmt.Println("set: ", a) + fmt.Println("len: ", len(a)) + + //b := [5]int{1, 2, 3, 4, 5} + 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) +} diff --git a/atomic-counters.go b/atomic-counters.go new file mode 100644 index 0000000..74375ca --- /dev/null +++ b/atomic-counters.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "runtime" + "sync/atomic" + "time" +) + +func main() { + var ops uint64 = 0 + for i := 0; i < 50; i++ { + go func() { + for { + atomic.AddUint64(&ops, 1) + runtime.Gosched() + } + }() + } + time.Sleep(time.Second) + + opsFinal := atomic.LoadUint64(&ops) + fmt.Println("ops: ", opsFinal) +} diff --git a/base64-encoding.go b/base64-encoding.go new file mode 100644 index 0000000..7a73047 --- /dev/null +++ b/base64-encoding.go @@ -0,0 +1,21 @@ +package main + +import ( + b64 "encoding/base64" + "fmt" +) + +func main() { + data := "abc123!%^*&(*)_+)!@#" + sEnc := b64.StdEncoding.EncodeToString([]byte(data)) + fmt.Println(sEnc) + + sDec, _ := b64.StdEncoding.DecodeString(sEnc) + fmt.Println(string(sDec)) + fmt.Println() + // This encodes/decodes using a URL-compatible base64 format. + uEnc := b64.URLEncoding.EncodeToString([]byte(data)) + fmt.Println(uEnc) + uDec, _ := b64.URLEncoding.DecodeString(uEnc) + fmt.Println(string(uDec)) +} diff --git a/channel-buffering.go b/channel-buffering.go new file mode 100644 index 0000000..a7aa514 --- /dev/null +++ b/channel-buffering.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" +) + +func main() { + messages := make(chan string, 2) + + messages <- "buffered" + fmt.Println(<-messages) + messages <- "channel" + messages <- "channel" + + fmt.Println(<-messages) + fmt.Println(<-messages) +} diff --git a/channel-directions.go b/channel-directions.go new file mode 100644 index 0000000..6d1b396 --- /dev/null +++ b/channel-directions.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" +) + +// This ping function only accepts a channel for sending values. It would be a compile-time error to try to receive on this channel. +func ping(pings chan<- string, msg string) { + pings <- msg +} + +// The pong function accepts one channel for receives (pings) and a second for sends (pongs). +func pong(pings <-chan string, pongs chan<- string) { + msg := <-pings + pongs <- msg +} + +func main() { + pings := make(chan string, 1) + pongs := make(chan string, 1) + ping(pings, "passed message") + pong(pings, pongs) + fmt.Println(<-pongs) +} diff --git a/channel-synchronization.go b/channel-synchronization.go new file mode 100644 index 0000000..a42ab2f --- /dev/null +++ b/channel-synchronization.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "time" +) + +func worker(done chan bool) { + fmt.Println("working...") + time.Sleep(time.Second) + fmt.Println("done") + done <- true +} + +func main() { + done := make(chan bool, 1) // Start a worker goroutine, giving it the channel to notify on. + + go worker(done) + //Block until we receive a notification from the worker on the channel. + <-done +} + +// This is the function we’ll run in a goroutine. +// The done channel will be used to notify another goroutine that this +// function’s work is done. +// Send a value to notify that we’re done. + +// If you removed the <- done line from this program, +// the program would exit before the worker even started. diff --git a/closing-channels.go b/closing-channels.go new file mode 100644 index 0000000..d323b0a --- /dev/null +++ b/closing-channels.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "time" +) + +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 // chan 要在不同的goroutine中 + return + } + } + }() + + for j := 1; j <= 3; j++ { + jobs <- j + fmt.Println("sent job", j) + time.Sleep(time.Second * 1) + } + //This sends 3 jobs to the worker over the jobs channel, then closes it. + close(jobs) + fmt.Println("sent all jobs") + <-done // chan 要在不同的goroutine中 +} diff --git a/closures.go b/closures.go new file mode 100644 index 0000000..0dc9655 --- /dev/null +++ b/closures.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" +) + +func intSeq(a int) func() int { + i := 0 + return func() int { + a += 1 + i += a + 1 + return i + } +} + +func main() { + n := intSeq(2) + fmt.Println(n()) + fmt.Println(n()) //这一次会直接进入到闭包中执行,闭包外的 i:=0 这行代码不会被执行。闭包中的变量结果都会被保留并带入下一个闭包代码执行 + fmt.Println(n()) + fmt.Println(n()) + + m := intSeq(2) + fmt.Println(m()) //另一个新的函数开始,和前面那个闭包毫无关系 + fmt.Println(n()) +} diff --git a/collection-functions.go b/collection-functions.go new file mode 100644 index 0000000..e0236f4 --- /dev/null +++ b/collection-functions.go @@ -0,0 +1,72 @@ +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)) +} diff --git a/command-line-arguments.go b/command-line-arguments.go new file mode 100644 index 0000000..196ee97 --- /dev/null +++ b/command-line-arguments.go @@ -0,0 +1,15 @@ +package main + +import "os" +import "fmt" + +func main() { + // os.Args provides access to raw command-line arguments. Note that the first value in this slice is the path to the program, and os.Args[1:] holds the arguments to the program. + argsWithProg := os.Args + argsWithoutProg := os.Args[1:] + // You can get individual args with normal indexing. + arg := os.Args[3] + fmt.Println(argsWithProg) + fmt.Println(argsWithoutProg) + fmt.Println(arg) +} diff --git a/command-line-flags.go b/command-line-flags.go new file mode 100644 index 0000000..3d9aad9 --- /dev/null +++ b/command-line-flags.go @@ -0,0 +1,24 @@ +package main + +// Go provides a flag package supporting basic command-line flag parsing. We’ll use this package to implement our example command-line program. +import "flag" +import "fmt" + +func main() { + // Basic flag declarations are available for string, integer, and boolean options. Here we declare a string flag word with a default value "foo" and a short description. This flag.String function returns a string pointer (not a string value); we’ll see how to use this pointer below. + wordPtr := flag.String("word", "foo", "a string") + // This declares numb and fork flags, using a similar approach to the word flag. + numbPtr := flag.Int("numb", 42, "an int") + boolPtr := flag.Bool("fork", false, "a bool") + // It’s also possible to declare an option that uses an existing var declared elsewhere in the program. Note that we need to pass in a pointer to the flag declaration function. + var svar string + flag.StringVar(&svar, "svar", "bar", "a string var") + // Once all flags are declared, call flag.Parse() to execute the command-line parsing. + flag.Parse() + // Here we’ll just dump out the parsed options and any trailing positional arguments. Note that we need to dereference the pointers with e.g. *wordPtr to get the actual option values. + fmt.Println("word:", *wordPtr) + fmt.Println("numb:", *numbPtr) + fmt.Println("fork:", *boolPtr) + fmt.Println("svar:", svar) + fmt.Println("tail:", flag.Args()) +} diff --git a/defer.go b/defer.go new file mode 100644 index 0000000..945dc0b --- /dev/null +++ b/defer.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + f := createFile("/tmp/defer.txt") + defer closeFile(f) + writeFile(f) +} + +func createFile(p string) *os.File { + fmt.Println("Creating") + f, err := os.Create(p) + if err != nil { + panic(err) + } + return f +} + +func writeFile(f *os.File) { + fmt.Println("Writing") + fmt.Fprintln(f, "data") +} + +func closeFile(f *os.File) { + fmt.Println("Closing") + f.Close() +} diff --git a/environment-variables.go b/environment-variables.go new file mode 100644 index 0000000..1e0d5d9 --- /dev/null +++ b/environment-variables.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + os.Setenv("FOO", "1") + fmt.Println("FOO: ", os.Getenv("FOO")) + fmt.Println("BAR: ", os.Getenv("BAR")) + + fmt.Println() + for _, e := range os.Environ() { + pair := strings.Split(e, "=") + fmt.Println(pair[0]) + } +} diff --git a/epoch.go b/epoch.go new file mode 100644 index 0000000..17b6c46 --- /dev/null +++ b/epoch.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + // Use time.Now with Unix or UnixNano to get elapsed time since the Unix epoch in seconds or nanoseconds, respectively. + now := time.Now() + secs := now.Unix() + nanos := now.UnixNano() + fmt.Println(now) + // Note that there is no UnixMillis, so to get the milliseconds since epoch you’ll need to manually divide from nanoseconds. + millis := nanos / 1000000 + fmt.Println(secs) + fmt.Println(millis) + fmt.Println(nanos) + // You can also convert integer seconds or nanoseconds since the epoch into the corresponding time. + fmt.Println(time.Unix(secs, 0)) + fmt.Println(time.Unix(0, nanos)) +} + +// 2012-10-31 16:13:58.292387 +0000 UTC +// 1351700038 +// 1351700038292 +// 1351700038292387000 +// 2012-10-31 16:13:58 +0000 UTC +// 2012-10-31 16:13:58.292387 +0000 UTC diff --git a/error.go b/error.go new file mode 100644 index 0000000..34a1b19 --- /dev/null +++ b/error.go @@ -0,0 +1,51 @@ +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) + } +} diff --git a/execing-processes.go b/execing-processes.go new file mode 100644 index 0000000..07c759d --- /dev/null +++ b/execing-processes.go @@ -0,0 +1,22 @@ +package main + +import "syscall" +import "os" +import "os/exec" + +func main() { + // For our example we’ll exec ls. Go requires an absolute path to the binary we want to execute, so we’ll use exec.LookPath to find it (probably /bin/ls). + binary, lookErr := exec.LookPath("ls") + if lookErr != nil { + panic(lookErr) + } + // Exec requires arguments in slice form (as apposed to one big string). We’ll give ls a few common arguments. Note that the first argument should be the program name. + args := []string{"ls", "-a", "-l", "-h"} + // Exec also needs a set of environment variables to use. Here we just provide our current environment. + env := os.Environ() + // Here’s the actual syscall.Exec call. If this call is successful, the execution of our process will end here and be replaced by the /bin/ls -a -l -h process. If there is an error we’ll get a return value. + execErr := syscall.Exec(binary, args, env) + if execErr != nil { + panic(execErr) + } +} diff --git a/exit.go b/exit.go new file mode 100644 index 0000000..6a084c2 --- /dev/null +++ b/exit.go @@ -0,0 +1,11 @@ +package main + +import "fmt" +import "os" + +func main() { + // defers will not be run when using os.Exit, so this fmt.Println will never be called. + defer fmt.Println("!") + // Exit with status 3. + os.Exit(3) +} diff --git a/for.go b/for.go new file mode 100644 index 0000000..902498a --- /dev/null +++ b/for.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + i := 1 + for i <= 3 { + fmt.Println(i) + i = i + 1 + } +} diff --git a/function.go b/function.go new file mode 100644 index 0000000..b84fcf0 --- /dev/null +++ b/function.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" +) + +func plus(a int, b int) int { + return a + b +} +func main() { + res := plus(1, 2) + fmt.Println("1+2 = ", res) +} diff --git a/goroutine.go b/goroutine.go new file mode 100644 index 0000000..bbbb735 --- /dev/null +++ b/goroutine.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +func f(from string) { + for i := 0; i < 3; i++ { + fmt.Println(from, ":", i) + } +} + +func main() { + f("direct") + go f("goroutine") + go func(msg string) { + fmt.Println(msg) + }("going") + + var input string + fmt.Scanln(&input) + fmt.Println("done") +} diff --git a/if_else.go b/if_else.go new file mode 100644 index 0000000..fd6530e --- /dev/null +++ b/if_else.go @@ -0,0 +1,19 @@ +package main + +import "fmt" + +func main() { + if 7%2 == 0 { + fmt.Println("7 is even") + } else { + fmt.Println("7 is odd") + } + + if num := 9; num < 0 { + fmt.Println(num, "is negative") + } else if num < 10 { + fmt.Println(num, "has 1 digit") + } else { + fmt.Println(num, "has multiple digits") + } +} diff --git a/interface.go b/interface.go new file mode 100644 index 0000000..08e7b7d --- /dev/null +++ b/interface.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "math" +) + +type geometry interface { // 任何类型 包括struct 都可以调用interface中的方法。可以看出interface是类型的父类 + area() float64 // rect 和 circle的方法名相同,但是根据类型不同调用不同代码 + 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("here: ", g) + fmt.Println(g.area()) // rect 和 circle的方法名相同,但是根据类型不同调用不同代码 + fmt.Println(g.perim()) +} + +func main() { + r := rect{width: 10, height: 10} + c := circle{radius: 5} + + measure(&r) + measure(c) +} + +// 接口: 接口中集成很多方法,或嵌套接口。在使用的时候,根据传的类型的不同,调用其该类型定义的方法 +// go中没有继承, 所以用接口可以模拟实现类的继承。 可以看成interface就是父类, 子类调用其中的方法时,就是调用该对应子类的方法 diff --git a/json.go b/json.go new file mode 100644 index 0000000..0303b51 --- /dev/null +++ b/json.go @@ -0,0 +1,91 @@ +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) + // We can also decode JSON into custom data types. This has the advantages of adding additional type-safety to our programs and eliminating the need for type assertions when accessing the decoded data. + str := `{"page": 1, "fruits": ["apple", "peach"]}` + res := Response2{} + json.Unmarshal([]byte(str), &res) + fmt.Println(res) + fmt.Println(res.Fruits[0]) + // In the examples above we always used bytes and strings as intermediates between the data and JSON representation on standard out. We can also stream JSON encodings directly to os.Writers like os.Stdout or even HTTP response bodies. + 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} diff --git a/map.go b/map.go new file mode 100644 index 0000000..b9a5001 --- /dev/null +++ b/map.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" +) + +func main() { + m := make(map[string]int) + + m["k1"] = 7 + m["k2"] = 13 + + fmt.Println("map: ", 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(n) +} diff --git a/method.go b/method.go new file mode 100644 index 0000000..2a21376 --- /dev/null +++ b/method.go @@ -0,0 +1,45 @@ +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 (r *rect) padd(a int) int { //方法不能有多个返回值, 函数可以有多个返回值 + fmt.Println("width: ", r.width) + r.width += a + return r.width +} + +func (r rect) iadd(a int) int { + fmt.Println("width: ", r.width) + r.width += a + return r.width // r.width 只是在这个范围中 被修改了, 实际struct中的 width是没有被修改的 +} + +func main() { + r := rect{width: 10, height: 10} + + fmt.Println("area: ", r.area()) + fmt.Println("perim:", r.perim()) + rp := &r + fmt.Println("area: ", rp.area()) + fmt.Println("perim:", rp.perim()) + + a := 10 + fmt.Println("iadd: ", r.iadd(a)) + fmt.Println("padd: ", r.padd(a)) + fmt.Println("padd: ", r.padd(a)) + +} diff --git a/multiple-return-values.go b/multiple-return-values.go new file mode 100644 index 0000000..3c92704 --- /dev/null +++ b/multiple-return-values.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" +) + +func vals() (int, int) { + return 3, 7 +} + +func main() { + a, b := vals() + fmt.Println(a) + fmt.Println(b) +} diff --git a/mutex.go b/mutex.go new file mode 100644 index 0000000..3194d11 --- /dev/null +++ b/mutex.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "math/rand" + "runtime" + "sync" + "sync/atomic" + "time" +) + +func main() { + var state = make(map[int]int) + var mutex = &sync.Mutex{} + + var ops int64 = 0 + + for r := 0; r < 100; r++ { + go func() { + total := 0 + for { + key := rand.Intn(5) + mutex.Lock() + total += state[key] + mutex.Unlock() + atomic.AddInt64(&ops, 1) + runtime.Gosched() + } + }() + } + + 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.AddInt64(&ops, 1) + runtime.Gosched() + } + }() + } + time.Sleep(time.Second) + opsFinal := atomic.LoadInt64(&ops) + fmt.Println("ops:", opsFinal) + mutex.Lock() + fmt.Println("state:", state) + mutex.Unlock() +} diff --git a/non-blocking-channel-operations.go b/non-blocking-channel-operations.go new file mode 100644 index 0000000..2cd53b1 --- /dev/null +++ b/non-blocking-channel-operations.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + messages := make(chan string) + signals := make(chan bool) + + go func() { + messages <- "result" + }() + + time.Sleep(time.Second * 1) + + msg := "hi" + select { + case messages <- msg: + fmt.Println("sent message", msg) + default: + fmt.Println("no message sent") + } + select { + case msg := <-messages: + fmt.Println("received messages", msg) + default: + fmt.Println("no messages received") + } + + select { + case msg := <-messages: + fmt.Println("received message", msg) + case sig := <-signals: + fmt.Println("received signal", sig) + default: + fmt.Println("no activity") + } +} + +// Basic sends and receives on channels are blocking. +// However, we can use select with a default clause to +// implement non-blocking sends, receives, and even non-blocking multi-way selects. diff --git a/number-parsing.go b/number-parsing.go new file mode 100644 index 0000000..54e2f6c --- /dev/null +++ b/number-parsing.go @@ -0,0 +1,24 @@ +package main +The built-in package strconv provides the number parsing. +import "strconv" +import "fmt" +func main() { +// With ParseFloat, this 64 tells how many bits of precision to parse. + f, _ := strconv.ParseFloat("1.234", 64) + fmt.Println(f) +// For ParseInt, the 0 means infer the base from the string. 64 requires that the result fit in 64 bits. + i, _ := strconv.ParseInt("123", 0, 64) + fmt.Println(i) +// ParseInt will recognize hex-formatted numbers. + d, _ := strconv.ParseInt("0x1c8", 0, 64) + fmt.Println(d) +// A ParseUint is also available. + u, _ := strconv.ParseUint("789", 0, 64) + fmt.Println(u) +// Atoi is a convenience function for basic base-10 int parsing. + k, _ := strconv.Atoi("135") + fmt.Println(k) +// Parse functions return an error on bad input. + _, e := strconv.Atoi("wat") + fmt.Println(e) +} \ No newline at end of file diff --git a/page_url.txt b/page_url.txt new file mode 100644 index 0000000..cf0dca5 --- /dev/null +++ b/page_url.txt @@ -0,0 +1 @@ +https://gobyexample.com/ \ No newline at end of file diff --git a/panic.go b/panic.go new file mode 100644 index 0000000..8a1ce27 --- /dev/null +++ b/panic.go @@ -0,0 +1,13 @@ +package main + +import "os" + +func main() { + panic("a problem") + _, err := os.Create("/tmp/file") + if err != nil { + panic(err) + } +} + +// A common use of panic is to abort if a function returns an error value that we don’t know how to (or want to) handle. Here’s an example of panicking if we get an unexpected error when creating a new file. diff --git a/pointer.go b/pointer.go new file mode 100644 index 0000000..9a0322c --- /dev/null +++ b/pointer.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" +) + +func zeroval(ival int) { + ival = 0 +} + +func zeroptr(iptr *int) { + *iptr = 0 +} + +func main() { + i := 1 + fmt.Println("initial:", i) + zeroval(i) + fmt.Println("zeroval:", i) + + zeroptr(&i) + fmt.Println("zeroptr:", i) + fmt.Println("pointer:", &i) //每一次都随机分配过 指针地址 +} diff --git a/random-numbers.go b/random-numbers.go new file mode 100644 index 0000000..d804b5b --- /dev/null +++ b/random-numbers.go @@ -0,0 +1,43 @@ +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() + // 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() + 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 diff --git a/range-over-channels.go b/range-over-channels.go new file mode 100644 index 0000000..c1f8347 --- /dev/null +++ b/range-over-channels.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" +) + +func main() { + queue := make(chan string, 2) + queue <- "one" + queue <- "two" // chan 在同一个GOroutine中 + close(queue) + + for elem := range queue { + fmt.Println(elem) + } +} diff --git a/range.go b/range.go new file mode 100644 index 0000000..68ab334 --- /dev/null +++ b/range.go @@ -0,0 +1,28 @@ +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 { + sum += nums[i] + if num == 3 { + fmt.Println("index: ", i) + } + } + kvs := map[string]string{"a": "apple", "b": "banana"} + for k, v := range kvs { + fmt.Println("%s-> %s\n", k, v) + } + for i, c := range "go" { + fmt.Println(i, c) + } +} diff --git a/rate-limiting.go b/rate-limiting.go new file mode 100644 index 0000000..796c4f6 --- /dev/null +++ b/rate-limiting.go @@ -0,0 +1,43 @@ +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(time.Millisecond * 200) + + for req := range requests { + <-limiter + fmt.Println("requests", 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(time.Millisecond * 200) { + 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()) + } +} diff --git a/reading-files.go b/reading-files.go new file mode 100644 index 0000000..fad74bb --- /dev/null +++ b/reading-files.go @@ -0,0 +1,52 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "os" +) + +// Reading files requires checking most calls for errors. This helper will streamline our error checks below. +func check(e error) { + if e != nil { + panic(e) + } +} + +func main() { + // Perhaps the most basic file reading task is slurping a file’s entire contents into memory. + dat, err := ioutil.ReadFile("/tmp/dat") + check(err) + fmt.Print(string(dat)) + // You’ll often want more control over how and what parts of a file are read. For these tasks, start by Opening a file to obtain an os.File value. + f, err := os.Open("/tmp/dat") + check(err) + // Read some bytes from the beginning of the file. Allow up to 5 to be read but also note how many actually were read. + b1 := make([]byte, 5) + n1, err := f.Read(b1) + check(err) + fmt.Printf("%d bytes: %s\n", n1, string(b1)) + // You can also Seek to a known location in the file and Read from there. + o2, err := f.Seek(6, 0) + check(err) + b2 := make([]byte, 2) + n2, err := f.Read(b2) + check(err) + fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2)) + + // The io package provides some functions that may be helpful for file reading. For example, reads like the ones above can be more robustly implemented with ReadAtLeast + o3, err := f.Seek(6, 0) + check(err) + b3 := make([]byte, 4) + n3, err := io.ReadAtLeast(f, b3, 4) + check(err) + fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) + // The bufio package implements a buffered reader that may be useful both for its efficiency with many small reads and because of the additional reading methods it provides./ + r4 := bufio.NewReader(f) + b4, err := r4.Peek(5) + check(err) + fmt.Printf("5 bytes: %s\n", string(b4)) + defer f.Close() +} diff --git a/recursion.go b/recursion.go new file mode 100644 index 0000000..8209e04 --- /dev/null +++ b/recursion.go @@ -0,0 +1,16 @@ +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)) +} diff --git a/regular-expressions.go b/regular-expressions.go new file mode 100644 index 0000000..3b5aca1 --- /dev/null +++ b/regular-expressions.go @@ -0,0 +1,42 @@ +package main + +import ( + "bytes" + "fmt" + "regexp" +) + +func main() { + // This tests whether a pattern matches a string. + match, _ := regexp.MatchString("p([a-z]+)ch", "peach") + fmt.Println(match) + // Above we used a string pattern directly, but for other regexp tasks you’ll need to Compile an optimized Regexp struct. + r, _ := regexp.Compile("p([a-z]+)ch") + // Many methods are available on these structs. Here’s a match test like we saw earlier. + fmt.Println(r.MatchString("peach")) + // This finds the match for the regexp. + fmt.Println(r.FindString("peach punch")) + // This also finds the first match but returns the start and end indexes for the match instead of the matching text. + fmt.Println(r.FindStringIndex("peach punch")) + // The Submatch variants include information about both the whole-pattern matches and the submatches within those matches. For example this will return information for both p([a-z]+)ch and ([a-z]+). + fmt.Println(r.FindStringSubmatch("peach punch")) + // Similarly this will return information about the indexes of matches and submatches. + fmt.Println(r.FindStringSubmatchIndex("peach punch")) + // The All variants of these functions apply to all matches in the input, not just the first. For example to find all matches for a regexp. + fmt.Println(r.FindAllString("peach punch pinch", -1)) + // These All variants are available for the other functions we saw above as well. + fmt.Println(r.FindAllStringSubmatchIndex("peach punch pinch", -1)) + // Providing a non-negative integer as the second argument to these functions will limit the number of matches. + fmt.Println(r.FindAllString("peach punch pinch", 2)) + // Our examples above had string arguments and used names like MatchString. We can also provide []byte arguments and drop String from the function name. + fmt.Println(r.Match([]byte("peach"))) + // When creating constants with regular expressions you can use the MustCompile variation of Compile. A plain Compile won’t work for constants because it has 2 return values. + r = regexp.MustCompile("p([a-z]+)ch") + fmt.Println(r) + // The regexp package can also be used to replace subsets of strings with other values. + fmt.Println(r.ReplaceAllString("a peach", "")) + // The Func variant allows you to transform matched text with a given function. + in := []byte("a peach") + out := r.ReplaceAllFunc(in, bytes.ToUpper) + fmt.Println(string(out)) +} diff --git a/select.go b/select.go new file mode 100644 index 0000000..42fe503 --- /dev/null +++ b/select.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + c1 := make(chan string) + c2 := make(chan string) + + go func() { + time.Sleep(time.Second * 1) + c1 <- "one" + }() + go func() { + time.Sleep(time.Second * 2) + c2 <- "two" + }() + + for i := 0; i < 2; i++ { + select { + case msg1 := <-c1: + fmt.Println("received", msg1) + case msg2 := <-c2: + fmt.Println("received", msg2) + } + } + +// Each channel will receive a value after some amount of time, +// to simulate e.g. blocking RPC operations executing in concurrent goroutines. +// We’ll use select to await both of these values simultaneously, +// printing each one as it arrives.We receive the values "one" and then "two" as expected +// Note that the total execution time is only ~2 seconds since both the 1 and 2 second Sleeps execute concurrently. \ No newline at end of file diff --git a/sha1-hashes.go b/sha1-hashes.go new file mode 100644 index 0000000..828a76a --- /dev/null +++ b/sha1-hashes.go @@ -0,0 +1,20 @@ +package main + +import ( + "crypto/sha1" + "fmt" +) + +func main() { + s := "sha1 this string" + // The pattern for generating a hash is sha1.New(), sha1.Write(bytes), then sha1.Sum([]byte{}). Here we start with a new hash. + h := sha1.New() + // Write expects bytes. If you have a string s, use []byte(s) to coerce it to bytes. + // This gets the finalized hash result as a byte slice. The argument to Sum can be used to append to an existing byte slice: it usually isn’t needed. + h.Write([]byte(s)) + + bs := h.Sum(nil) + + fmt.Println(s) + fmt.Printf("%x\n", bs) +} diff --git a/signals.go b/signals.go new file mode 100644 index 0000000..a705b70 --- /dev/null +++ b/signals.go @@ -0,0 +1,34 @@ +package main + +import "fmt" +import "os" +import "os/signal" +import "syscall" + +// Sometimes we’d like our Go programs to intelligently handle Unix signals. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool to stop processing input if it receives a SIGINT. Here’s how to handle signals in Go with channels. + +func main() { + // Go signal notification works by sending os.Signal values on a channel. We’ll create a channel to receive these notifications (we’ll also make one to notify us when the program can exit). + sigs := make(chan os.Signal, 1) + done := make(chan bool, 1) + // signal.Notify registers the given channel to receive notifications of the specified signals. + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + // This goroutine executes a blocking receive for signals. When it gets one it’ll print it out and then notify the program that it can finish. + go func() { + sig := <-sigs + fmt.Println() + fmt.Println(sig) + done <- true + }() + // The program will wait here until it gets the expected signal (as indicated by the goroutine above sending a value on done) and then exit. + fmt.Println("awaiting signal") + <-done + fmt.Println("exiting") +} + +// When we run this program it will block waiting for a signal. By typing ctrl-C (which the terminal shows as ^C) we can send a SIGINT signal, causing the program to print interrupt and then exit. +// $ go run signals.go +// awaiting signal +// ^C +// interrupt +// exiting diff --git a/slice.go b/slice.go new file mode 100644 index 0000000..0d78f32 --- /dev/null +++ b/slice.go @@ -0,0 +1,27 @@ +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(cap(s)) + fmt.Println(s) + + s = append(s, "d") + s = append(s, "e", "f") + fmt.Println(cap(s)) + fmt.Println(s) + + c := make([]string, len(s)) + copy(c, s) + fmt.Println("cpy: ", c) + + l := s[1:] + fmt.Println(l) +} diff --git a/sorting-by-functions.go b/sorting-by-functions.go new file mode 100644 index 0000000..d66570c --- /dev/null +++ b/sorting-by-functions.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "sort" +) + +type ByLength []string + +func (s ByLength) Len() int { + return len(s) +} + +func (s ByLength) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s ByLength) Less(i, j int) bool { + return len(s[i]) < len(s[j]) +} + +func main() { + fruits := []string{"peach", "banana", "kiwi"} + fmt.Println(ByLength(fruits)) + sort.Sort(ByLength(fruits)) + fmt.Println(fruits) +} + +// We implement sort.Interface - Len, Less, and Swap - on our type so we can use the sort package’s +// generic Sort function. Len and Swap will usually be similar across types and Less will hold the actual +// custom sorting logic. In our case we want to sort in order of increasing string length, +// so we use len(s[i]) and len(s[j]) here. diff --git a/sorting.go b/sorting.go new file mode 100644 index 0000000..06bad66 --- /dev/null +++ b/sorting.go @@ -0,0 +1,17 @@ +package main + +import "fmt" +import "sort" + +func main() { + strs := []string{"c", "a", "b"} + sort.Strings(strs) + fmt.Println("Strings: ", strs) + + ints := []int{7, 2, 6} + sort.Ints(ints) + fmt.Println("Ints: ", ints) + + s := sort.IntsAreSorted(ints) + fmt.Println("Sorted: ", s) +} diff --git a/spawning-processes.go b/spawning-processes.go new file mode 100644 index 0000000..4853154 --- /dev/null +++ b/spawning-processes.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os/exec" +) + +func main() { + dateCmd := exec.Command("date") + + dateOut, err := dateCmd.Output() + if err != nil { + panic(err) + } + fmt.Println("> date") + fmt.Println(string(dateOut)) + + grepCmd := exec.Command("grep", "hello") + + grepIn, _ := grepCmd.StdinPipe() + grepOut, _ := grepCmd.StdoutPipe() + grepCmd.Start() + grepIn.Write([]byte("hello grep\ngoodbye grep")) + grepIn.Close() + grepBytes, _ := ioutil.ReadAll(grepOut) + grepCmd.Wait() + // We ommited error checks in the above example, but you could use the usual if err != nil pattern for all of them. We also only collect the StdoutPipe results, but you could collect the StderrPipe in exactly the same way. + fmt.Println("> grep hello") + fmt.Println(string(grepBytes)) + // Note that when spawning commands we need to provide an explicitly delineated command and argument array, vs. being able to just pass in one command-line string. If you want to spawn a full command with a string, you can use bash’s -c option: + lsCmd := exec.Command("bash", "-c", "ls -a -l -h") + lsOut, err := lsCmd.Output() + if err != nil { + panic(err) + } + fmt.Println("> ls -a -l -h") + fmt.Println(string(lsOut)) +} diff --git a/string-formatting.go b/string-formatting.go new file mode 100644 index 0000000..647a446 --- /dev/null +++ b/string-formatting.go @@ -0,0 +1,82 @@ +package main + +import "fmt" +import "os" + +type point struct { + x, y int +} + +func main() { + // Go offers several printing “verbs” designed to format general Go values. For example, this prints an instance of our point struct. + p := point{1, 2} + fmt.Printf("%v\n", p) + // If the value is a struct, the %+v variant will include the struct’s field names. + fmt.Printf("%+v\n", p) + // The %#v variant prints a Go syntax representation of the value, i.e. the source code snippet that would produce that value. + fmt.Printf("%#v\n", p) + // To print the type of a value, use %T. + fmt.Printf("%T\n", p) + // Formatting booleans is straight-forward. + fmt.Printf("%t\n", true) + // There are many options for formatting integers. Use %d for standard, base-10 formatting. + fmt.Printf("%d\n", 123) + // This prints a binary representation. + fmt.Printf("%b\n", 14) + // This prints the character corresponding to the given integer. + fmt.Printf("%c\n", 33) + // %x provides hex encoding. + fmt.Printf("%x\n", 456) + // There are also several formatting options for floats. For basic decimal formatting use %f. + fmt.Printf("%f\n", 78.9) + // %e and %E format the float in (slightly different versions of) scientific notation. + fmt.Printf("%e\n", 123400000.0) + fmt.Printf("%E\n", 123400000.0) + // For basic string printing use %s. + fmt.Printf("%s\n", "\"string\"") + // To double-quote strings as in Go source, use %q. + fmt.Printf("%q\n", "\"string\"") + // As with integers seen earlier, %x renders the string in base-16, with two output characters per byte of input. + fmt.Printf("%x\n", "hex this") + // To print a representation of a pointer, use %p. + fmt.Printf("%p\n", &p) + // When formatting numbers you will often want to control the width and precision of the resulting figure. To specify the width of an integer, use a number after the % in the verb. By default the result will be right-justified and padded with spaces. + fmt.Printf("|%6d|%6d|\n", 12, 345) + + fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45) + // To left-justify, use the - flag. + fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45) + // You may also want to control width when formatting strings, especially to ensure that they align in table-like output. For basic right-justified width. + fmt.Printf("|%6s|%6s|\n", "foo", "b") + // To left-justify use the - flag as with numbers. + fmt.Printf("|%-6s|%-6s|\n", "foo", "b") + // So far we’ve seen Printf, which prints the formatted string to os.Stdout. Sprintf formats and returns a string without printing it anywhere. + s := fmt.Sprintf("a %s", "string") + fmt.Println(s) + // You can format+print to io.Writers other than os.Stdout using Fprintf. + 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 diff --git a/string-functions.go b/string-functions.go new file mode 100644 index 0000000..a63e2c9 --- /dev/null +++ b/string-functions.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + ss "strings" +) + +var p = fmt.Println + +func main() { + p("Contains: ", ss.Contains("test", "es")) + p("Count: ", ss.Count("test", "t")) + p("HasPrefix: ", ss.HasPrefix("test", "te")) + p("Index: ", ss.HasSuffix("test", "st")) + p("Join: ", ss.Join([]string{"a", "b"}, "-")) + p("Repeat: ", ss.Repeat("a", 5)) + p("Replace: ", ss.Replace("foo", "o", "0", -1)) + p("Replace: ", ss.Replace("foo", "o", "0", 1)) + p("Split: ", ss.Split("a-b-c-d-e", "-")) + p("ToLower: ", ss.ToLower("TEST")) + p("ToUpper: ", ss.ToUpper("test")) + p() + p("Len: ", len("hello")) + p("Char:", "hello"[1]) +} diff --git a/switch.go b/switch.go new file mode 100644 index 0000000..17b13fb --- /dev/null +++ b/switch.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + i := 2 + fmt.Println("write ", i, " as ") + switch i { + case 1: + fmt.Println("one") + case 2: + fmt.Println("two") + case 3: + fmt.Println("three") + } + + switch time.Now().Weekday() { + case time.Saturday, time.Sunday: + fmt.Println("it's the weekend") + default: + fmt.Println("it's a weekday") + } + + t := time.Now() + switch { + case t.Hour() < 12: + fmt.Println("it is before noon") + default: + fmt.Println("it is after noon") + } +} diff --git a/tickers.go b/tickers.go new file mode 100644 index 0000000..3653ab9 --- /dev/null +++ b/tickers.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ticker := time.NewTicker(time.Millisecond * 500) + go func() { + for t := range ticker.C { + fmt.Println("Tick at", t) + } + }() + + time.Sleep(time.Millisecond * 1600) + ticker.Stop() + fmt.Println("Ticker stopped") +} + +//Tickers use a similar mechanism to timers: a channel that is sent values. +// Here we’ll use the range builtin on the channel to iterate over the values as they arrive every 500ms. +//Tickers can be stopped like timers. Once a ticker is stopped it won’t receive any +// more values on its channel. We’ll stop ours after 1600ms diff --git a/time-formatting-parsing.go b/time-formatting-parsing.go new file mode 100644 index 0000000..f89d826 --- /dev/null +++ b/time-formatting-parsing.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + p := fmt.Println + + t := time.Now() + p(t.Format(time.RFC3339)) + + t1, e := time.Passe( + 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) + // For purely numeric representations you can also use standard string formatting with the extracted components of the time value. + fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n", + t.Year(), t.Month(), t.Day(), + t.Hour(), t.Minute(), t.Second()) + // Parse will return an error on malformed input explaining the parsing problem. + 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": ... diff --git a/timeouts.go b/timeouts.go new file mode 100644 index 0000000..442e8ab --- /dev/null +++ b/timeouts.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + c1 := make(chan string, 1) + go func() { + time.Sleep(time.Second * 2) + c1 <- "result 1" + }() + + select { + case res := <-c1: + fmt.Println(res) + case <-time.After(time.Second * 1): + fmt.Println("timeout 1") + } + + c2 := make(chan string, 1) + go func() { + time.Sleep(time.Second * 2) + c2 <- "result 2" + }() + select { + case res := <-c2: + fmt.Println(res) + case <-time.After(time.Second * 3): + fmt.Println("timeout 2") + } +} + +//Using this select timeout pattern requires communicating results over channels. This is a good idea in general because other important Go features are based on channels and select. diff --git a/timers.go b/timers.go new file mode 100644 index 0000000..cb03287 --- /dev/null +++ b/timers.go @@ -0,0 +1,23 @@ +package main + +import "time" +import "fmt" + +func main() { + timer1 := time.NewTimer(time.Second * 2) + <-timer1.C + fmt.Println("Timer 1 expired") + timer2 := time.NewTimer(time.Second) + go func() { + <-timer2.C + fmt.Println("Timer 2 expired") + }() + stop2 := timer2.Stop() + if stop2 { + fmt.Println("Timer 2 stopped") + } +} + +//We often want to execute Go code at some point in the future, or repeatedly at some interval. +// Go’s built-in timer and ticker features make both of these tasks easy. We’ll look first at timers and then at tickers. +//f you just wanted to wait, you could have used time.Sleep. One reason a timer may be useful is that you can cancel the timer before it expires. Here’s an example of that. diff --git a/times.go b/times.go new file mode 100644 index 0000000..7c9f6ab --- /dev/null +++ b/times.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + p := fmt.Println + // We’ll start by getting the current time. + now := time.Now() + p(now) + // You can build a time struct by providing the year, month, day, etc. Times are always associated with a Location, i.e. time zone. + then := time.Date( + 2009, 11, 17, 20, 34, 58, 651387237, time.UTC) + p(then) + // You can extract the various components of the time value as expected. + p(then.Year()) + p(then.Month()) + p(then.Day()) + p(then.Hour()) + p(then.Minute()) + p(then.Second()) + p(then.Nanosecond()) + p(then.Location()) + // The Monday-Sunday Weekday is also available. + p(then.Weekday()) + // These methods compare two times, testing if the first occurs before, after, or at the same time as the second, respectively. + p(then.Before(now)) + p(then.After(now)) + p(then.Equal(now)) + // The Sub methods returns a Duration representing the interval between two times. + diff := now.Sub(then) + p(diff) + // We can compute the length of the duration in various units. + p(diff.Hours()) + p(diff.Minutes()) + p(diff.Seconds()) + p(diff.Nanoseconds()) + // You can use Add to advance a time by a given duration, or with a - to move backwards by a duration. + 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 diff --git a/url-parsing.go b/url-parsing.go new file mode 100644 index 0000000..d530deb --- /dev/null +++ b/url-parsing.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "net" + "net/url" +) + +func main() { + s := "postgres://user:pass@host.com:5432/path?k=v#" + + u, err := url.Parse(s) + 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) + + // The Host contains both the hostname and the port, if present. Use SplitHostPort to extract them. + fmt.Println(u.Host) + host, port, _ := net.SplitHostPort(u.Host) + fmt.Println(host) + fmt.Println(port) + // Here we extract the path and the fragment after the #. + fmt.Println(u.Path) + fmt.Println(u.Fragment) + // To get query params in a string of k=v format, use RawQuery. You can also parse query params into a map. The parsed query param maps are from strings to slices of strings, so index into [0] if you only want the first value. + fmt.Println(u.RawQuery) + m, _ := url.ParseQuery(u.RawQuery) + fmt.Println(m) + fmt.Println(m["k"][0]) + + u2 := "https://www.google.com" + + i, _ := url.Parse(u2) + + fmt.Println(i) + fmt.Println(i.Scheme) + fmt.Println(i.Host) +} diff --git a/wait-group.go b/wait-group.go new file mode 100644 index 0000000..980f9d4 --- /dev/null +++ b/wait-group.go @@ -0,0 +1,26 @@ +package main + +import "fmt" +import "sync" + +var wg sync.WaitGroup // 1 + +func routine(i int) { + defer wg.Done() // 3 + fmt.Printf("routine %v finished\n", i) +} + +func main() { + for i := 0; i < 10; i++ { + wg.Add(1) // 2 + go routine(i) // * + } + wg.Wait() // 4 + fmt.Println("main finished") +} + +// WaitGroup usage in order of execution. +// Declaration of global variable. Making it global is the easiest way to make it visible to all functions and methods. +// Increasing the counter. This must be done in main goroutine because there is no guarantee that newly started goroutine will execute before 4 due to memory model guarantees. +// Decreasing the counter. This must be done at the exit of goroutine. Using deferred call, we make sure that it will be called whenever function ends no matter but no matter how it ends. +// Waiting for the counter to reach 0. This must be done in main goroutine to prevent program exit. diff --git a/worker-pools.go b/worker-pools.go new file mode 100644 index 0000000..56f1807 --- /dev/null +++ b/worker-pools.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "time" +) + +func worker(id int, jobs <-chan int, results chan<- int) { + for j := range jobs { + fmt.Println("worker", id, " processing job", j) + time.Sleep(time.Second) + results <- j * 2 + } +} +func main() { + jobs := make(chan int, 100) + results := make(chan int, 100) + + // In order to use our pool of workers we need to send them work and collect their results. We make 2 channels for this. + + // This starts up 3 workers, initially blocked because there are no jobs yet. + for w := 1; w <= 3; w++ { + go worker(w, jobs, results) + } + + //Here we send 9 jobs and then close that channel to indicate that’s all the work we have. + for j := 1; j <= 9; j++ { + jobs <- j + } + close(jobs) + + //Finally we collect all the results of the work + for a := 1; a <= 9; a++ { + fmt.Println(<-results) + } +} diff --git a/writing-files.go b/writing-files.go new file mode 100644 index 0000000..20783b1 --- /dev/null +++ b/writing-files.go @@ -0,0 +1,42 @@ +package main + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" +) + +func check(e error) { + if e != nil { + panic(e) + } +} + +func main() { + d1 := []byte("hello\ngo\n") + // To start, here’s how to dump a string (or just bytes) into a file. + err := ioutil.WriteFile("/tmp/dat1", d1, 0644) + check(err) + + f, err := os.Create("/tmp/dat2") + check(err) + // It’s idiomatic to defer a Close immediately after opening a file. + defer f.Close() + + d2 := []byte{115, 111, 109, 101, 10} + n2, err := f.Write(d2) + check(err) + fmt.Printf("wrote %d bytes\n", n2) + // A WriteString is also available. + n3, err := f.WriteString("hallo\n") + fmt.Printf("wrote %d bytes\n", n3) + f.Sync() + + w := bufio.NewWriter(f) + n4, err := w.WriteString("buffered\n") + fmt.Printf("wrote %d bytes\n", n4) + + // Use Flush to ensure all buffered operations have been applied to the underlying writer. + w.Flush() +}