├── 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 |
--------------------------------------------------------------------------------