├── basic ├── branch │ ├── abc.txt │ └── branch.go ├── regex │ └── regex.go ├── loop │ └── loop.go ├── basic │ └── basic.go └── func │ └── func.go ├── tree ├── traversal.go ├── node.go └── entry │ └── entry.go ├── functional ├── fib │ └── fib.go ├── adder │ └── adder.go └── main.go ├── queue ├── entry │ └── main.go └── queue.go ├── goroutine └── goroutine.go ├── retriever ├── mock │ └── retriever.go ├── real │ └── retriever.go └── main.go ├── channel ├── test │ └── channel_tets.go └── channel.go ├── container ├── nonrepeatingsubstr │ └── nonrepeating.go ├── strings │ └── strings.go ├── slices │ ├── sliceops.go │ └── slices.go ├── arrays │ └── arrays.go └── maps │ └── maps.go └── README.md /basic/branch/abc.txt: -------------------------------------------------------------------------------- 1 | aaa 2 | zzz 3 | xxx 4 | lll 5 | -------------------------------------------------------------------------------- /tree/traversal.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | // 中序遍历 4 | func (node *Node) Traverse() { 5 | if node == nil { 6 | return 7 | } 8 | node.Left.Traverse() 9 | node.Print() 10 | node.Right.Traverse() 11 | } 12 | -------------------------------------------------------------------------------- /functional/fib/fib.go: -------------------------------------------------------------------------------- 1 | package fib 2 | 3 | // 实现斐波那契数列 4 | // 1, 1, 2, 3, 5, 8, 13, ... 5 | func Fibonacci() func() int { 6 | a, b := 0, 1 7 | return func() int { 8 | a, b = b, a+b 9 | return a 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /queue/entry/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "learngo/queue" 6 | ) 7 | 8 | func main() { 9 | q := queue.Queue{1} 10 | 11 | q.Push(2) 12 | q.Push(3) 13 | fmt.Println(q.Pop()) 14 | fmt.Println(q.Pop()) 15 | fmt.Println(q.IsEmpty()) 16 | fmt.Println(q.Pop()) 17 | fmt.Println(q.IsEmpty()) 18 | } 19 | -------------------------------------------------------------------------------- /goroutine/goroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // goroutine与协程Coroutine相似 9 | func main() { 10 | for i := 0; i < 1000; i++ { 11 | go func(i int) { 12 | for { 13 | fmt.Printf("Hello from "+ 14 | "goroutine %d\n", i) 15 | } 16 | }(i) 17 | } 18 | time.Sleep(time.Millisecond) 19 | } 20 | -------------------------------------------------------------------------------- /basic/regex/regex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | const text = ` 9 | My email is xl94.zhang@gmail.com 10 | email1 is abc.d@def.org 11 | emial2 is kkk.g@qqq.com 12 | ` 13 | 14 | func main() { 15 | re := regexp.MustCompile( 16 | `[a-zA-Z0-9]+\.[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+`) 17 | match := re.FindAllString(text, -1) 18 | fmt.Println(match) 19 | } 20 | -------------------------------------------------------------------------------- /queue/queue.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | // 扩充类型方法2:使用别名 4 | 5 | // 定义切片,含有三个变量 first, len, cap 6 | type Queue []int 7 | 8 | func (q *Queue) Push(v int) { 9 | // q = append(q, v),此时出错,q为地址而不是append所需的slice 10 | *q = append(*q, v) 11 | } 12 | 13 | func (q *Queue) Pop() int { 14 | head := (*q)[0] 15 | *q = (*q)[1:] 16 | return head 17 | } 18 | 19 | func (q *Queue) IsEmpty() bool { 20 | return len(*q) == 0 21 | } 22 | -------------------------------------------------------------------------------- /retriever/mock/retriever.go: -------------------------------------------------------------------------------- 1 | package mock 2 | 3 | import "fmt" 4 | 5 | type Retriever struct { 6 | Contents string 7 | } 8 | 9 | func (r *Retriever) String() string { 10 | return fmt.Sprintf( 11 | "Retriever: {Contents=%s}", r.Contents) 12 | } 13 | 14 | func (r *Retriever) Post(url string, 15 | form map[string]string) string { 16 | r.Contents = form["contents"] 17 | return "ok" 18 | } 19 | 20 | func (r *Retriever) Get(url string) string { 21 | return r.Contents 22 | } 23 | -------------------------------------------------------------------------------- /retriever/real/retriever.go: -------------------------------------------------------------------------------- 1 | package real 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httputil" 6 | "time" 7 | ) 8 | 9 | type Retriever struct { 10 | UserAgent string 11 | TimeOut time.Duration 12 | } 13 | 14 | func (r *Retriever) Get(url string) string { 15 | resp, err := http.Get(url) 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | result, err := httputil.DumpResponse(resp, true) 21 | resp.Body.Close() 22 | 23 | if err != nil { 24 | panic(err) 25 | } 26 | return string(result) 27 | } 28 | -------------------------------------------------------------------------------- /tree/node.go: -------------------------------------------------------------------------------- 1 | package tree 2 | 3 | import "fmt" 4 | 5 | // 定义结构体 6 | type Node struct { 7 | Value int 8 | Left, Right *Node 9 | } 10 | 11 | // 打印节点的值,(node node)是接收者,表示Print()方法是给node来用的 12 | func (node Node) Print() { 13 | fmt.Print(node.Value, " ") 14 | } 15 | 16 | // 设置节点的值 17 | func (node *Node) SetValue(value int) { 18 | if node == nil { 19 | fmt.Println("Setting Value to nil " + 20 | "node. Ignored.") 21 | return 22 | } 23 | node.Value = value 24 | } 25 | 26 | // 自定义工厂函数:相当于自己写的构造函数。go没有构造函数 27 | func CreateNode(value int) *Node { 28 | // 可以返回局部变量的地址 29 | return &Node{Value: value} 30 | } 31 | -------------------------------------------------------------------------------- /channel/test/channel_tets.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func worker(id int, c chan int) { 9 | for { 10 | fmt.Printf("Worker %d received %c\n", 11 | id, <-c) 12 | } 13 | } 14 | 15 | func chanDemo() { 16 | var channels [10]chan int 17 | for i := 0; i < 10; i++ { 18 | channels[i] = make(chan int) 19 | go worker(i, channels[i]) 20 | } 21 | 22 | for i := 0; i < 10; i++ { 23 | channels[i] <- 'a' + i 24 | } 25 | 26 | for i := 0; i < 10; i++ { 27 | channels[i] <- 'A' + i 28 | } 29 | 30 | time.Sleep(time.Millisecond) 31 | } 32 | 33 | func main() { 34 | chanDemo() 35 | } 36 | -------------------------------------------------------------------------------- /container/nonrepeatingsubstr/nonrepeating.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func lengthOfNonRepeatingSubStr(s string) int { 6 | lastOccurred := make(map[rune]int) 7 | start := 0 8 | maxLength := 0 9 | 10 | for i, ch := range []rune(s) { 11 | if lastI, ok := lastOccurred[ch]; ok && lastI >= start { 12 | start = lastI + 1 13 | } 14 | if i-start+1 > maxLength { 15 | maxLength = i - start + 1 16 | } 17 | lastOccurred[ch] = i 18 | } 19 | return maxLength 20 | } 21 | 22 | // 寻找最长不含有重复字符的子串,包含中文字符串 23 | func main() { 24 | fmt.Println( 25 | lengthOfNonRepeatingSubStr("abcabcbb")) 26 | fmt.Println( 27 | lengthOfNonRepeatingSubStr("东南大学南京大学")) 28 | } 29 | -------------------------------------------------------------------------------- /functional/adder/adder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 实现一 6 | func adder() func(int) int { 7 | sum := 0 8 | return func(v int) int { 9 | sum += v 10 | return sum 11 | } 12 | } 13 | 14 | // 实现二 15 | type iAdder func(int) (int, iAdder) 16 | 17 | func adder2(base int) iAdder { 18 | return func(v int) (int, iAdder) { 19 | return base + v, adder2(base + v) 20 | } 21 | } 22 | 23 | func main() { 24 | // 实现一 25 | a := adder() 26 | for i := 0; i < 10; i++ { 27 | fmt.Printf("0 + 1 + ... + %d = %d\n", 28 | i, a(i)) 29 | } 30 | 31 | // 实现二 32 | b := adder2(0) 33 | for i := 0; i < 10; i++ { 34 | var s int 35 | s, b = b(i) 36 | fmt.Printf("0 + 1 + ... + %d = %d\n", 37 | i, s) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /functional/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "learngo/functional/fib" 8 | "strings" 9 | ) 10 | 11 | type intGen func() int 12 | 13 | // 给类添加接口快捷键: alt+shift+p 14 | func (g intGen) Read(p []byte) (n int, err error) { 15 | next := g() 16 | if next > 10000 { 17 | return 0, io.EOF 18 | } 19 | s := fmt.Sprintf("%d\n", next) 20 | 21 | // TODO: incorrect if p is too small! 22 | return strings.NewReader(s).Read(p) 23 | } 24 | 25 | func printFileContents(reader io.Reader) { 26 | scanner := bufio.NewScanner(reader) 27 | 28 | for scanner.Scan() { 29 | fmt.Println(scanner.Text()) 30 | } 31 | } 32 | 33 | func main() { 34 | var f intGen = fib.Fibonacci() 35 | printFileContents(f) 36 | } 37 | -------------------------------------------------------------------------------- /container/strings/strings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | // go中解决中文 9 | func main() { 10 | s := "东大研究生" // 汉字 3 byte 11 | fmt.Println(s) 12 | 13 | for _, b := range []byte(s) { 14 | fmt.Printf("%X ", b) 15 | } 16 | fmt.Println() 17 | 18 | for i, ch := range s { // ch is a rune, rune is 32bit 19 | fmt.Printf("(%d %X)", i, ch) 20 | } 21 | fmt.Println() 22 | 23 | fmt.Println("Rune count:", 24 | utf8.RuneCountInString(s)) 25 | 26 | bytes := []byte(s) 27 | for len(bytes) > 0 { 28 | ch, size := utf8.DecodeRune(bytes) 29 | bytes = bytes[size:] 30 | fmt.Printf("%c ", ch) 31 | } 32 | fmt.Println() 33 | 34 | for i, ch := range []rune(s) { 35 | fmt.Printf("(%d %c) ", i, ch) 36 | } 37 | fmt.Println() 38 | } 39 | -------------------------------------------------------------------------------- /channel/channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // 此时channel,即可收又可发:func createWorker(id int) chan int 9 | // 此时channel只可收, <-chan为此时只可发 10 | func createWorker(id int) chan<- int { 11 | c := make(chan int) 12 | go func() { 13 | for { 14 | fmt.Printf("Worker %d received %c\n", 15 | id, <-c) 16 | } 17 | }() 18 | return c 19 | } 20 | 21 | func chanDemo() { 22 | var channels [10]chan<- int 23 | // 创建10个channel 24 | for i := 0; i < 10; i++ { 25 | channels[i] = createWorker(i) 26 | } 27 | 28 | for i := 0; i < 10; i++ { 29 | channels[i] <- 'a' + i 30 | } 31 | 32 | for i := 0; i < 10; i++ { 33 | channels[i] <- 'A' + i 34 | } 35 | 36 | time.Sleep(time.Millisecond) 37 | } 38 | 39 | func main() { 40 | chanDemo() 41 | } 42 | -------------------------------------------------------------------------------- /basic/branch/branch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | ) 7 | 8 | func grade(score int) string { 9 | g := "" 10 | switch { 11 | case score < 0 || score > 100: 12 | panic(fmt.Sprintf( 13 | "wrong score: %d", score)) 14 | case score < 60: 15 | g = "F" 16 | case score < 80: 17 | g = "C" 18 | case score < 90: 19 | g = "B" 20 | case score <= 100: 21 | g = "A" 22 | } 23 | return g 24 | } 25 | 26 | func main() { 27 | const filename = "abc.txt" 28 | if contents, err := ioutil.ReadFile(filename); err != nil { 29 | fmt.Println(err) 30 | } else { 31 | fmt.Printf("%s\n", contents) 32 | } 33 | 34 | fmt.Println( 35 | grade(0), 36 | grade(59), 37 | grade(60), 38 | grade(82), 39 | grade(99), 40 | grade(100), 41 | // Uncomment to see it panics. 42 | // grade(-3), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /container/slices/sliceops.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func printSlice(s []int) { 6 | // cap成倍增加 7 | fmt.Printf("%v, len=%d, cap=%d\n", 8 | s, len(s), cap(s)) 9 | } 10 | 11 | func main() { 12 | fmt.Println("Creating slice") 13 | var s []int // Zero value for slice is nil 14 | 15 | for i := 0; i < 100; i++ { 16 | printSlice(s) 17 | s = append(s, 2*i+1) 18 | } 19 | fmt.Println(s) 20 | 21 | s1 := []int{2, 4, 6, 8} 22 | printSlice(s1) 23 | 24 | s2 := make([]int, 16) 25 | s3 := make([]int, 10, 32) 26 | printSlice(s2) 27 | printSlice(s3) 28 | 29 | fmt.Println("Copying slice") 30 | copy(s2, s1) 31 | printSlice(s2) 32 | 33 | fmt.Println("Deleting elements from slice") 34 | s2 = append(s2[:3], s2[4:]...) 35 | printSlice(s2) 36 | 37 | fmt.Println("Popping from front") 38 | front := s2[0] 39 | s2 = s2[1:] 40 | 41 | fmt.Println(front) 42 | printSlice(s2) 43 | 44 | fmt.Println("Popping from back") 45 | tail := s2[len(s2)-1] 46 | s2 = s2[:len(s2)-1] 47 | 48 | fmt.Println(tail) 49 | printSlice(s2) 50 | } 51 | -------------------------------------------------------------------------------- /container/arrays/arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func printArray(arr [5]int) { 6 | arr[0] = 100 7 | for i, v := range arr { 8 | fmt.Println(i, v) 9 | } 10 | } 11 | 12 | func printArrayByPointer(arr *[5]int) { 13 | // (*arr)[0] = 100 14 | arr[0] = 100 15 | for i, v := range arr { 16 | fmt.Println(i, v) 17 | } 18 | } 19 | 20 | func main() { 21 | var arr1 [5]int 22 | arr2 := [3]int{1, 3, 5} 23 | arr3 := [...]int{2, 4, 6, 8, 10} 24 | var grid [4][5]int 25 | 26 | fmt.Println(arr1, arr2, arr3) 27 | fmt.Println(grid) 28 | 29 | for i := 0; i < len(arr3); i++ { 30 | fmt.Println(arr3[i]) 31 | } 32 | 33 | // range的使用 34 | for i := range arr3 { 35 | fmt.Println(arr3[i]) 36 | } 37 | for i, v := range arr3 { 38 | fmt.Println(i, v) 39 | } 40 | for _, v := range arr3 { 41 | fmt.Println(v) 42 | } 43 | 44 | fmt.Println("printArray(arr1)") 45 | printArray(arr1) 46 | 47 | fmt.Println("printArrayByPointer(arr3)") 48 | printArrayByPointer(&arr3) 49 | 50 | fmt.Println("arr1 and arr3") 51 | fmt.Println(arr1, arr3) 52 | } 53 | -------------------------------------------------------------------------------- /container/maps/maps.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | m := map[string]string{ 7 | "name": "ccmouse", 8 | "course": "golang", 9 | "site": "imooc", 10 | "quality": "notbad", 11 | } 12 | 13 | m2 := make(map[string]int) // m2 == empty map 14 | var m3 map[string]int // m3 == nil 15 | 16 | fmt.Println("m, m2, m3:") 17 | fmt.Println(m, m2, m3) 18 | 19 | fmt.Println("Traversing map m") 20 | for k, v := range m { 21 | fmt.Println(k, v) 22 | } 23 | 24 | fmt.Println("Getting values") 25 | courseName := m["course"] 26 | // 在Go语言中不倾向于使用单引号来表示字符串,请根据需要使用双引号或反引号 27 | fmt.Println(`m["course"]=`, courseName) 28 | if causeName, ok := m["cause"]; ok { 29 | fmt.Println(causeName) 30 | } else { 31 | fmt.Println("key 'cause' does not exist") 32 | } 33 | 34 | fmt.Println("Deleting values") 35 | name, ok := m["name"] 36 | fmt.Printf("m[%q] before delete: %q, %v\n", 37 | "name", name, ok) 38 | 39 | delete(m, "name") 40 | name, ok = m["name"] 41 | fmt.Printf("m[%q] after delete: %q, %v\n", 42 | "name", name, ok) 43 | } 44 | -------------------------------------------------------------------------------- /container/slices/slices.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func updateSlice(s []int) { 6 | s[0] = 100 7 | } 8 | 9 | func main() { 10 | arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7} 11 | 12 | fmt.Println("arr[2:6] =", arr[2:6]) 13 | fmt.Println("arr[:6] =", arr[:6]) 14 | s1 := arr[2:] 15 | fmt.Println("s1 =", s1) 16 | s2 := arr[:] 17 | fmt.Println("s2 =", s2) 18 | 19 | fmt.Println("After updateSlice(s1)") 20 | updateSlice(s1) 21 | fmt.Println(s1) 22 | fmt.Println(arr) 23 | 24 | fmt.Println("After updateSlice(s2)") 25 | updateSlice(s2) 26 | fmt.Println(s2) 27 | fmt.Println(arr) 28 | 29 | fmt.Println("Reslice") 30 | fmt.Println(s2) 31 | s2 = s2[:5] 32 | fmt.Println(s2) 33 | s2 = s2[2:] 34 | fmt.Println(s2) 35 | 36 | fmt.Println("Extending slice") 37 | arr[0], arr[2] = 0, 2 38 | fmt.Println("arr =", arr) 39 | s1 = arr[2:6] 40 | s2 = s1[3:5] 41 | fmt.Println("s1=%v, len(s1)=%d, cap(s1)=%d\n", 42 | s1, len(s1), cap(s1)) 43 | fmt.Println("s2=%v, len(s2)=%d, cap(s2)=%d\n", 44 | s2, len(s2), cap(s2)) 45 | 46 | s3 := append(s2, 10) 47 | s4 := append(s3, 11) 48 | s5 := append(s4, 12) 49 | fmt.Println("s3, s4, s5 =", s3, s4, s5) 50 | fmt.Println("arr=", arr) 51 | } 52 | -------------------------------------------------------------------------------- /basic/loop/loop.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func convertToBin(n int) string { 13 | result := "" 14 | for ; n > 0; n /= 2 { 15 | lsb := n % 2 16 | result = strconv.Itoa(lsb) + result 17 | } 18 | return result 19 | } 20 | 21 | func printFile(filename string) { 22 | file, err := os.Open(filename) 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | printFileContents(file) 28 | } 29 | 30 | func printFileContents(reader io.Reader) { 31 | scanner := bufio.NewScanner(reader) 32 | for scanner.Scan() { 33 | fmt.Println(scanner.Text()) 34 | } 35 | } 36 | 37 | func forever() { 38 | for { 39 | fmt.Println("abc") 40 | } 41 | } 42 | 43 | func main() { 44 | fmt.Println("convertToBin results:") 45 | fmt.Println( 46 | convertToBin(5), // 101 47 | convertToBin(13), // 1101 48 | convertToBin(72387885), 49 | convertToBin(0), 50 | ) 51 | 52 | fmt.Println("abc.txt contents:") 53 | printFile("abc.txt") 54 | 55 | fmt.Println("printing a string:") 56 | s := `abc"d" 57 | kkkk 58 | 123 59 | 60 | p` 61 | printFileContents(strings.NewReader(s)) 62 | 63 | // Uncomment to see it runs forever 64 | // forever() 65 | } 66 | -------------------------------------------------------------------------------- /tree/entry/entry.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "learngo/tree" 6 | ) 7 | 8 | // 扩充类型方法1:组合方式 9 | type myTreeNode struct { 10 | node *tree.Node 11 | } 12 | 13 | // 后序遍历 14 | func (myNode *myTreeNode) postOrder() { 15 | if myNode == nil || myNode.node == nil { 16 | return 17 | } 18 | left := myTreeNode{myNode.node.Left} 19 | right := myTreeNode{myNode.node.Right} 20 | 21 | left.postOrder() 22 | right.postOrder() 23 | myNode.node.Print() 24 | } 25 | 26 | func main() { 27 | nodes := []tree.Node{ 28 | {Value: 3}, 29 | {}, 30 | {6, nil, nil}, 31 | } 32 | 33 | fmt.Println(nodes) 34 | var root tree.Node 35 | root.Left = &tree.Node{} 36 | root.Right = &tree.Node{5, nil, nil} 37 | // 使用new与上面的效果一致 38 | root.Right.Left = new(tree.Node) 39 | root.Left.Right = tree.CreateNode(2) 40 | fmt.Println(root) 41 | 42 | root.Right.Left.SetValue(4) 43 | root.Right.Left.Print() 44 | 45 | // 值接收者传地址也可以,自动取值出来使用 46 | pRoot := &root 47 | pRoot.Print() 48 | pRoot.SetValue(200) 49 | pRoot.Print() 50 | // nil指针也可以调用方法 51 | fmt.Println("use nil ptr:") 52 | var pRoot2 *tree.Node 53 | pRoot2.SetValue(200) 54 | pRoot2 = &root 55 | pRoot2.SetValue(300) 56 | pRoot2.Print() 57 | 58 | fmt.Println("Pre Traversing:") 59 | root.Traverse() 60 | fmt.Println() 61 | 62 | // 扩充类型方法1:组合方式 63 | fmt.Println("Post Traversing:") 64 | myRoot := myTreeNode{&root} 65 | myRoot.postOrder() 66 | fmt.Println() 67 | } 68 | -------------------------------------------------------------------------------- /basic/basic/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/cmplx" 7 | ) 8 | 9 | var ( 10 | aa = 3 11 | ss = "kkk" 12 | bb = true 13 | ) 14 | 15 | func variableZeroValue() { 16 | var a int 17 | var s string 18 | fmt.Printf("%d %q\n", a, s) 19 | } 20 | 21 | func variableInitialValue() { 22 | var a, b, c, s = 3, 4, true, "def" 23 | fmt.Println(a, b, c, s) 24 | } 25 | 26 | func variableShorter() { 27 | a, b, c, s := 3, 4, true, "def" 28 | b = 5 29 | fmt.Println(a, b, c, s) 30 | } 31 | 32 | func variableTypeDeduction() { 33 | var a, b int = 3, 4 34 | var s string = "abc" 35 | fmt.Println(a, b, s) 36 | } 37 | 38 | func euler() { 39 | fmt.Printf("%.3f\n", 40 | cmplx.Exp(1i*math.Pi)+1) 41 | } 42 | 43 | func triangle() { 44 | var a, b int = 3, 4 45 | var c int 46 | // 类型转换是强制的 47 | c = int(math.Sqrt(float64(a*a + b*b))) 48 | fmt.Println(c) 49 | } 50 | 51 | const filename = "abc.txt" 52 | 53 | func consts() { 54 | const a, b = 3, 4 55 | var c int 56 | c = int(math.Sqrt(a*a + b*b)) 57 | fmt.Println(filename, c) 58 | } 59 | 60 | func enums() { 61 | const ( 62 | cpp = 0 63 | java = 1 64 | python = 2 65 | golang = 3 66 | ) 67 | 68 | const ( 69 | cpp1 = iota 70 | _ 71 | java1 = 1 72 | python1 = 2 73 | golang1 = 3 74 | ) 75 | 76 | // b, kb, mb, gb, tb, pb 77 | const ( 78 | b = 1 << (10 * iota) 79 | // 下面依次也会执行 80 | kb 81 | mb 82 | gb 83 | tb 84 | pb 85 | ) 86 | 87 | fmt.Println(cpp, java, python, golang) 88 | fmt.Println(b, kb, mb, gb, tb, pb) 89 | } 90 | 91 | func main() { 92 | fmt.Println("hello world") 93 | variableZeroValue() 94 | variableInitialValue() 95 | variableInitialValue() 96 | variableShorter() 97 | fmt.Println(aa, ss, bb) 98 | euler() 99 | triangle() 100 | consts() 101 | enums() 102 | } 103 | -------------------------------------------------------------------------------- /retriever/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "learngo/retriever/mock" 6 | "learngo/retriever/real" 7 | "time" 8 | ) 9 | 10 | // 接口里面全是函数,不用加func关键字 11 | type Retriever interface { 12 | Get(url string) string 13 | } 14 | 15 | type Poster interface { 16 | Post(url string, 17 | form map[string]string) string 18 | } 19 | 20 | const url = "http://www.imooc.com" 21 | 22 | func download(r Retriever) string { 23 | return r.Get(url) 24 | } 25 | 26 | func post(poster Poster) { 27 | poster.Post(url, 28 | map[string]string{ 29 | "name": "ccmouse", 30 | "course": "golang", 31 | }) 32 | } 33 | 34 | type RetrieverPoster interface { 35 | Retriever 36 | Poster 37 | } 38 | 39 | func session(s RetrieverPoster) string { 40 | s.Post(url, map[string]string{ 41 | "contents": "another faked imooc.com", 42 | }) 43 | return s.Get(url) 44 | } 45 | 46 | func inspect(r Retriever) { 47 | fmt.Println("Inspecting", r) 48 | fmt.Printf(" > Type:%T Value:%v\n", r, r) 49 | fmt.Print(" > Type switch: ") 50 | switch v := r.(type) { 51 | case *mock.Retriever: 52 | fmt.Println("Contents:", v.Contents) 53 | case *real.Retriever: 54 | fmt.Println("UserAgent:", v.UserAgent) 55 | } 56 | fmt.Println() 57 | } 58 | 59 | func main() { 60 | var r Retriever 61 | 62 | mockRetriever := mock.Retriever{ 63 | Contents: "this is a fake imooc.com"} 64 | // (r *Retriever) Get(url string) string,即 Retriever的指针实现了接口的Get方法 65 | // 所以 &mockRetriever实现了接口,而 mockRetriever没有实现 66 | r = &mockRetriever 67 | inspect(r) 68 | 69 | r = &real.Retriever{ 70 | UserAgent: "Mozilla/5.0", 71 | TimeOut: time.Minute, 72 | } 73 | inspect(r) 74 | 75 | // Type assertion 76 | if mockRetriever, ok := r.(*mock.Retriever); ok { 77 | fmt.Println(mockRetriever.Contents) 78 | } else { 79 | fmt.Println("r is not a mock retriever") 80 | } 81 | fmt.Println( 82 | "Try a session with mockRetriever") 83 | fmt.Println(session(&mockRetriever)) 84 | } 85 | -------------------------------------------------------------------------------- /basic/func/func.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "reflect" 7 | "runtime" 8 | ) 9 | 10 | // 函数要点 11 | // 1. 返回值类型写在最后面 12 | // 2. 可返回多个值 13 | // 3. 函数作为参数 14 | // 4. 没有默认参数、可选参数等,只有可变参数列表 15 | 16 | // 值传递和引用传递 17 | // cpp中可以值传递也可以引用传递(&) 18 | // python和java除了系统内建类型是值传递以外,都是引用传递 19 | // golang只有值传递,要改变值必须用指针参数 20 | 21 | // 下划线表示变量不想用,其他变量名定义了不用会编译不过 22 | func eval(a, b int, op string) (int, error) { 23 | switch op { 24 | case "+": 25 | return a + b, nil 26 | case "-": 27 | return a - b, nil 28 | case "*": 29 | return a * b, nil 30 | case "/": 31 | q, _ := div(a, b) 32 | return q, nil 33 | default: 34 | return 0, fmt.Errorf( 35 | "unsupported operation: %s", op) 36 | } 37 | } 38 | 39 | // 两个返回值的三种写法 40 | // 1. 41 | // 13 / 3 = 4 ... 1 42 | //func div(a, b int) (int, int) { 43 | // return a / b, a % b 44 | //} 45 | 46 | // 2. 函数返回多个值时可以起名字,对于调用者而言没有区别 47 | func div(a, b int) (q, r int) { 48 | return a / b, a % b 49 | } 50 | 51 | // 3. 也可以,但不推荐。仅用于非常简单的函数 52 | //func div(a, b int) (q, r int) { 53 | // q = a / b 54 | // r = a % b 55 | // return 56 | //} 57 | 58 | // 函数作为参数 59 | func apply(op func(int, int) int, a, b int) int { 60 | p := reflect.ValueOf(op).Pointer() 61 | opName := runtime.FuncForPC(p).Name() 62 | fmt.Printf("calling function %s with args "+ 63 | "(%d, %d)\n", opName, a, b) 64 | return op(a, b) 65 | } 66 | 67 | // 可变参数列表 68 | func sum(numbers ...int) int { 69 | s := 0 70 | for i := range numbers { 71 | s += numbers[i] 72 | } 73 | return s 74 | } 75 | 76 | func swap(a, b int) (int, int) { 77 | return b, a 78 | } 79 | 80 | func main() { 81 | fmt.Println("Error handling") 82 | if result, err := eval(3, 4, "x"); err != nil { 83 | fmt.Println("Error:", err) 84 | } else { 85 | fmt.Println(result) 86 | } 87 | q, r := div(13, 3) 88 | fmt.Printf("13 div 3 is %d mod %d\n", q, r) 89 | 90 | fmt.Println("pow(3, 4) is:", apply( 91 | func(a int, b int) int { 92 | return int(math.Pow( 93 | float64(a), float64(b))) 94 | }, 3, 4)) 95 | 96 | fmt.Println("1+2+...+5 =", sum(1, 2, 3, 4, 5)) 97 | 98 | a, b := 3, 4 99 | a, b = swap(a, b) 100 | fmt.Println("a, b after swap is:", a, b) 101 | } 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go语言学习 2 | 3 | ## 一、Golang:变量定义([代码](https://github.com/ZzXxL1994/learngo/blob/master/basic/basic)) 4 | **1. 变量定义要点:** 5 | - 变量类型写在变量名之后 6 | - 编译器可推测变量类型 7 | - 没有char,只有rune 8 | - 原生支持复数类型 9 | 10 | **2. 内建变量类型:** 11 | - bool, string 12 | - (u)int, (u)int8, (u)int16, (u)int32, (u)int64, uintptr(指针) 13 | - byte, rune(就是char类型,为了应付多语言的一字节来设计,32位,与int32可混用) 14 | - float32, float64, complex64, complex128(表示实数,128表示实部和虚部分别是64位) 15 | 16 |
17 | 18 | ## 二、Golang:条件和循环([代码1](https://github.com/ZzXxL1994/learngo/tree/master/basic/branch),[代码2](https://github.com/ZzXxL1994/learngo/tree/master/basic/loop)) 19 | **条件、循环要点:** 20 | - for, if后面的条件没有括号 21 | - if条件里也可以定义变量 22 | - 没有while 23 | - switch不需要break,也可以直接switch多个条件 24 | 25 |
26 | 27 | ## 三、Golang:函数和指针([代码](https://github.com/ZzXxL1994/learngo/tree/master/basic/func)) 28 | **1. 函数要点:** 29 | - 返回值类型写在最后面 30 | - 可返回多个值 31 | - 函数作为参数 32 | - 没有默认参数、可选参数等,只有可变参数列表 33 | 34 | **2. 值传递和引用传递:** 35 | - cpp中可以值传递也可以引用传递(&) 36 | - python和java除了系统内建类型是值传递以外,都是引用传递 37 | - go只有值传递,要改变值必须用指针参数 38 | 39 |
40 | 41 | ## 四、Golang:内建容器([代码](https://github.com/ZzXxL1994/learngo/tree/master/container)) 42 | **1. 数组:** 43 | - 数组是值类型 44 | - [10]int和[20]int是不同的类型 45 | - 调用func f(arr [10]int)会拷贝数组。想改变原数组的值,用指针类型参数 46 | - go中一般不直接使用数组 47 | 48 | **2. 切片:** 49 | 50 | **3. Map:** 51 | - map的操作: 52 | - 创建:make(map[string]int) 53 | - 获取元素:m[key] 54 | - key不存在时,获得Value类型的初始值 55 | - 用value, ok:=m[key]来判断是否存在key 56 | - 用delete删除一个key 57 | - 使用len获得元素个数 58 | - map的遍历: 59 | - 用range遍历key,或者遍历key-value对 60 | - 不保证遍历顺利,如需顺序,需手动对key排序 61 | - map的key: 62 | - map使用哈希表,必须可以比较相等 63 | - 除了slice,map,function的内建类型都可以作为key 64 | - Struct类型中只要不包含上述三个字段,也可作为key 65 | 66 | **4. rune(go中的char):** 67 | - 使用range遍历pos-rune对 68 | - 使用utf8.RuneCountInString获得字符数量 69 | - 使用len获得字节长度 70 | - 使用[]byte获得字节 71 | 72 |
73 | 74 | ## 五、Golang:面向对象([代码1](https://github.com/ZzXxL1994/learngo/tree/master/tree),[代码2](https://github.com/ZzXxL1994/learngo/tree/master/queue)) 75 | **1. Go不能算是一种面向对象的语言:** 76 | - go只支持封装,不支持继承和多态 77 | - go只有struct,没有class 78 | 79 | **2. 结构(struct)创建在堆上还是栈上?** 80 | - cpp中,局部变量分配在栈上,在外界也要使用的变量要分配到堆上,并且要手动释放 81 | - java中,对象都分配在堆上,有对应的垃圾回收机制 82 | - go中不需要知道分配在堆上还是栈上。比如返回了局部变量的地址,那么是分配在堆上,并有对应的垃圾回收,这些都是编译器自己识别并实现的 83 | 84 | **3. 值接收者 vs 指针接收者:** 85 | - 要改变内容必须使用指针接收者 86 | - 结构过大也考虑使用指针接收者 87 | - 一致性:如果有指针接收者,最好都是指针接收者 88 | - 值接收者是go语言特有,值/指针接收者均可接受值/指针 89 | 90 | **4. 封装:** 91 | - 名字一般使用CamelCase形式 92 | - 首字母大写:public 93 | - 首字母小写:private 94 | - 首字母大小写是针对包(package)来说的 95 | 96 | **5. 包:** 97 | - 每个目录一个包 98 | - main包包含可执行入口,如果这个包里有main函数,那么这个目录下只能有一个main包 99 | - 为结构定义的方法必须放在同一个包内,可以是不同文件 100 | 101 | **6. 扩展系统类型或者别人的类型:** 102 | - 定义别名(见[代码](https://github.com/ZzXxL1994/learngo/blob/master/queue/queue.go)) 103 | - 使用组合(见[代码](https://github.com/ZzXxL1994/learngo/blob/master/tree/entry/entry.go)) 104 | 105 |
106 | 107 | ## 六、Golang:面向接口([代码](https://github.com/ZzXxL1994/learngo/tree/master/retriever)) 108 | **1. go语言的duck typing:** 109 | - 具有python,cpp的duck typing的灵活性 110 | - 又具有java的类型检查 111 | 112 | **2. 接口变量里有什么?** 113 | - 实现者的类型 114 | - 实现者的值(或指针指向实现者) 115 | 116 | **3. 注意:** 117 | - 接口变量里自带指针,接口变量本身采用值传递,几乎不需要使用接口的指针 118 | - 指针接收者实现只能以指针方式使用;值接收者都可以 119 | 120 |
121 | 122 | ## 七、Golang:函数式编程([代码](https://github.com/ZzXxL1994/learngo/tree/master/functional)) 123 | **1. 函数式编程 vs 函数指针:** 124 | - 函数是一等公民:参数,变量,返回值都可以是函数 125 | - 高阶函数 126 | - 函数->闭包 127 | 128 | **2. “正统”函数式编程:** 129 | - 不可变性:不能有状态,只有常量和函数 130 | - 函数只能有一个参数 131 | - go没有以上规定 132 | 133 | **3. go闭包的应用:** 134 | - 更为自然,不需要修饰如何访问自由变量 135 | - 没有lambda表达式,但是有匿名函数 136 | 137 |
138 | 139 | ## 八、Golang:goroutine([代码](https://github.com/ZzXxL1994/learngo/tree/master/goroutine)) 140 | **1. 与协程Coroutine相似:** 141 | - 轻量级“线程” 142 | - 非抢占式多任务处理,由协程主动交出控制权 143 | - 编译器/解释器/虚拟机层面的多任务 144 | - 多个协程可能在一个或多个线程上运行 145 | 146 | **2. goroutine的定义:** 147 | - 任何函数只需加上go就能送给调度器运行 148 | - 不需要在定义时区分是否是异步函数 149 | - 调度器在合适的点进行切换 150 | - 使用-race来检测数据访问冲突 151 | 152 | **3. goroutine可能的切换点(参考):** 153 | - I/O, select, channel 154 | - runtime.Gosched() 155 | - 等待锁,函数调用(有时) 156 | 157 |
158 | 159 | ## 九、Golang:channel([代码](https://github.com/ZzXxL1994/learngo/tree/master/channel)) 160 | **1. Groutine和channels实现了CSP(Communicating Sequential Processes)模型** 161 | 162 | **2. channles在goroutine的通信和同步中承担着重要的角色** 163 | 164 | **3. channel实现四个特性:** 165 | - goroutine安全 166 | - 在不同的goroutine之间存储和传输值 167 | - 提供FIFO语义(buffered channel提供) 168 | - 可以让goroutine block/unblock 169 | 170 | 171 | 172 | 173 | --------------------------------------------------------------------------------