Golang-C1-5

作业点评

sort.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
	"fmt"
	"sort"
)

type Student struct {
	Name string
	Id   int
}

func main() {
	s := []int{2, 3, 1, 5, 9, 7}
	sort.Slice(s, func(i, j int) bool {
		return s[i] < s[j]
	})

	ss := []Student{}
	ss = append(ss, Student{
		Name: "aa",
		Id:   2,
	})
	ss = append(ss, Student{
		Name: "cc",
		Id:   3,
	})
	ss = append(ss, Student{
		Name: "bb",
		Id:   1,
	})

	sort.Slice(ss, func(i, j int) bool {
		return ss[i].Name < ss[j].Name
	})

	fmt.Println(ss)
}

trim.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

type StringStruct struct {
	pointer *byte
	length  int
}

func main() {
	s := "hello\n"
	s1 := s[:len(s)-1]

	s1 = s
	s1.length -= 1
	fmt.Println(s)
	fmt.Println(s1)
}

set1.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import "fmt"

func main() {
	set := make(map[string]bool)
	set["a"] = true
	set["a"] = true
	if set["b"] {
		fmt.Println("ok")
	} else {
		fmt.Println("!ok")
	}
}

set.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import "fmt"

func main() {
	set := make(map[string]struct{})
	set["a"] = struct{}{}
	set["a"] = struct{}{}
	if _, ok := set["b"]; ok {
		fmt.Println("ok")
	} else {
		fmt.Println("!ok")
	}
}

反转

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
        "fmt"
        "strings"
)

type IntSlice []int

func main() {
        s := []int{1, 3, 5, 7, 9}
        fmt.Println(reverse_sliceside(s, 3))

        content := "a1 a2 a3 a4 a5"
        fmt.Println(reverse_words(content))
}

// 旋转切片两侧
func reverse_sliceside(c IntSlice, n int) IntSlice {
        s := append(c[n:], c[:n]...)
        return s
}

// 旋转单词
func reverse_words(content string) []string {
        slicea := strings.Fields(content)
        lenslicea := len(slicea)
        for i := lenslicea - 1; i >= 0; i-- {
                slicea = append(slicea, slicea[i])
        }
        return slicea[lenslicea:]
}

反转切片

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
	"fmt"
	"os"
)

func sliceJoin(s []int, target int) []int {
	return append(s[target:], s[:target]...)
}

func sliceJoin2(s []int, target int) []int {
	sz := len(s)
	for target != 0 {
		target--
		for i :=0; i<sz-1;i++ {
			s[i],s[i+1] = s[i+1],s[i]
		}
	}
	return s
}

func main() {
	a := []int{2,3,5,6,7,8,9,10}
	target := 2

        if target > len(a) || target < 0 {
                fmt.Println("target was invalid")
                os.Exit(1)
        }

        fmt.Println(sliceJoin(a, target))
        fmt.Println(sliceJoin2(a, target))
}

反转单词

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

package main

import (
        "fmt"
        "strings"
)

func main() {
        testStr := "The deepest shade of blue is waking up by your side"
        testStrSlice := strings.Split(testStr, " ")

        for i := 0; i < (len(testStrSlice) >> 1); i++ {
                mI := len(testStrSlice) - i - 1
                testStrSlice[i], testStrSlice[mI] = testStrSlice[mI], testStrSlice[i]
        }

        testStrRev := strings.Join(testStrSlice, " ")
        fmt.Println(testStrRev)
        // output: side your by up waking is blue of shade deepest The
}

信息管理

第1版

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

/*
完成学生信息管理系统

实现如下4个指令

1. add name id,添加一个学生的信息,如果name有重复,报错
2. list, 列出所有的学生信息
3. save filename,保存所有的学生信息到filename指定的文件中
4. load filename, filename指定的文件中加载学生信息

Code Example:

...
*/

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

type Student struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

type StudentSet struct {
	M map[string]*Student `json:"data"`
}

// NewStudentSets initial a new studentsets
func NewStudentSets() *StudentSet {
	return &StudentSet{M: make(map[string]*Student, 0)}
}

// Add student info
func (s *StudentSet) Add(id int, name string) (err error) {
	_, ok := s.M[name]
	if ok {
		err = fmt.Errorf("student %s already exists.", name)
		return
	}

	s.M[name] = &Student{Id: id, Name: name}

	return
}

// list all students info as a string
func (s *StudentSet) list() string {
	var str string = "Id\t\tName\n"
	for k, v := range s.M {
		str += fmt.Sprintf("%d\t\t%s\n", v.Id, k)
	}
	return str
}

// Remove student that specified
func (s *StudentSet) Remove(name string) {
	_, ok := s.M[name]
	if ok {
		delete(s.M, name)
	}
}

// Clear all students info
func (s *StudentSet) Clear() {
	s.M = make(map[string]*Student, 0)
}

// String implements String method
func (s *StudentSet) String() string {
	return s.list()
}

// Dump students info to the file that specified
func Dump(fileName string, stu *StudentSet) (err error) {
	fd, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return
	}
	defer fd.Close()

	bs, err := json.Marshal(stu)
	if err != nil {
		return
	}

	_, err = fd.Write(bs)
	if err != nil {
		return
	}

	return
}

// Load students info to the file that specified
func Load(fileName string) (stu *StudentSet, err error) {
	bs, err := ioutil.ReadFile(fileName)
	if err != nil {
		return
	}

	err = json.Unmarshal(bs, &stu)
	if err != nil {
		return
	}

	return
}

func errorHandler(err error) bool {
	var ok bool = true
	if err != nil {
		ok = false
		fmt.Println(err.Error())
		return ok
	}
	return ok
}

func main() {

	var (
		ok   bool
		cmd  string
		name string
		file string
		line string
		id   int
		err  error
	)

	f := bufio.NewReader(os.Stdin)
	stus := NewStudentSets()

	for {
		fmt.Print("> ")
		line, _ = f.ReadString('\n')
		fmt.Sscan(line, &cmd)
		switch cmd {
		case "list":
			fmt.Println(stus)

		case "add":
			fmt.Sscan(line, &cmd, &name, &id)
			err = stus.Add(id, name)
			if ok = errorHandler(err); ok {
				fmt.Printf("add done.\n")
			}

		case "save":
			fmt.Sscan(line, &cmd, &file)
			err = Dump(file, stus)
			if ok = errorHandler(err); ok {
				fmt.Printf("save student info to %s done\n", file)
			}

		case "load":
			fmt.Sscan(line, &cmd, &file)
			stus, err = Load(file)
			if ok = errorHandler(err); ok {
				fmt.Printf("load student info from %s done\n", file)
			}

		case "remove":
			fmt.Sscan(line, &cmd, &name)
			stus.Remove(name)
			fmt.Printf("remove student %s done\n", name)

		case "clear":
			fmt.Sscan(line, &cmd)
			stus.Clear()
			fmt.Printf("clear all students info done\n")

		case "exit", "quit", "q":
			os.Exit(0)

		default:
			fmt.Println("Usage: list|add|save|load|remove|clear|exit")
		}
	}

}

第2版

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type Student struct {
	Id   int
	Name string
}

func main() {
	var cmd string
	var filename string
	var name string
	var id int
	var line string
	finput := bufio.NewReader(os.Stdin)

	students := make(map[string]Student)
	for {
		fmt.Print("> ")
		line, _ = finput.ReadString('\n')
		fmt.Sscan(line, &cmd)
		switch cmd {
		case "list":
			for _, v := range students {
				fmt.Println(v.Name, v.Id)
			}
		case "add":
			fmt.Sscan(line, &cmd, &name, &id)
			// 判断add的学生是否已存在
			_, ok := students[name]
			if ok {
				fmt.Printf("%v 已存在!输入无效!\n", name)
				break
			} else {
				students[name] = Student{id, name} // map添加学生
			}
			fmt.Printf("add done.\n")
		case "save":
			fmt.Sscan(line, &cmd, &filename)
			json_obj, _ := json.Marshal(students) // 序列化,map转换成json
			f, err := os.Create(filename)         // 创建文件
			if err != nil {
				log.Fatal(err)
			}
			fmt.Fprint(f, string(json_obj)) // 写入json串
			f.Close()
			fmt.Printf("save to %v successful! \n", filename)
		case "load":
			fmt.Sscan(line, &cmd, &filename)
			filebuf, err := ioutil.ReadFile(filename) // 读文件
			if err != nil {
				fmt.Println(err)
				break
			}
			jsonerr := json.Unmarshal(filebuf, &students) // 反序列化,json转换成map
			if jsonerr != nil {
				fmt.Println(jsonerr)
			}
			fmt.Printf("load %v successful! \n", filename)
		default:
			fmt.Println("go ...")
		}
	}
}

第3版

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
)

type Student struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

var message = make(map[string]Student)

//处理异常输入信息
func handle(line string) (int, bool) {
	l := strings.TrimSpace(line)
	s := strings.Split(l, " ")
	if len(s) == 1 {
		switch s[0] {
		case "list", "add", "del", "change", "help", "exit":
			return len(s), true
		}
	}
	if len(s) == 2 {
		switch s[0] {
		case "save", "load":
			return len(s), true
		}
	}
	return len(s), false
}

func help() {
	fmt.Println("命令帮助: \n" +
		"\t显示信息:\tlist\n" +
		"\t增加信息:\tadd\n" +
		"\t删除信息:\tdel\n" +
		"\t修改信息:\tchange\n" +
		"\t保存信息:\tsave [filename]\n" +
		"\t加载信息:\tload [filename]\n" +
		"\t帮助信息:\thelp\n" +
		"\t退出程序:\texit")
}

func list() {
	for _, v := range message {
		fmt.Printf("%-10v\t%v\n", v.Name, v.Id)
	}
}

func add() {
	var name string
	var id string
	fmt.Println("请按如下格式添加:Name Id")
	fmt.Scan(&name, &id)
	if _, ok := message[name]; ok {
		fmt.Printf("\t**%v is Exist!**\n", name)
		return
	}
	n, err := strconv.Atoi(id)
	if err != nil {
		fmt.Println("Id not Int Type")
		return
	}
	message[name] = Student{
		Name: name,
		Id:   n,
	}
	fmt.Println("\t**Add is Ok!**")
}

func del() {
	var name string
	fmt.Println("请按如下格式添加:Name")
	fmt.Scan(&name)
	if _, ok := message[name]; ok {
		delete(message, name)
		fmt.Printf("\t**Delete %v is Ok!**\n", name)
	} else {
		fmt.Printf("\t**%v is not Exist!**\n", name)
	}
}

func change() {
	var name string
	var id string
	fmt.Println("请按如下格式添加:Name Id")
	fmt.Scan(&name, &id)
	if _, ok := message[name]; ok {
		n, err := strconv.Atoi(id)
		if err != nil {
			fmt.Println("Id not Int Type")
			return
		}
		tmp := message[name]
		tmp.Id = n
		message[name] = tmp
		fmt.Printf("\t**Change %v is Ok!**\n", name)
	} else {
		fmt.Printf("\t**%v is not Exist!**\n", name)
	}
}

func save(filename string) error {
	b, err := json.Marshal(message)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(filename, b, 0600)
	if err != nil {
		return err
	}
	fmt.Println("\t**Save is Ok!**")
	return nil
}

func load(filename string) error {
	message = make(map[string]Student)
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	err = json.Unmarshal(content, &message)
	if err != nil {
		return err
	}
	fmt.Println("\t**Load is Ok!**")
	return nil
}

func main() {
	for {
		var cmd string
		var line string
		var filename string
		f := bufio.NewReader(os.Stdin)
		fmt.Print("> ")
		line, _ = f.ReadString('\n')

		n, b := handle(line)
		if b {
			if n == 1 {
				fmt.Sscan(line, &cmd)
			} else if n == 2 {
				fmt.Sscan(line, &cmd, &filename)
			}
		} else {
			help()
			continue
		}

		switch cmd {
		case "list":
			list()
		case "add":
			add()
		case "del":
			del()
		case "change":
			change()
		case "save":
			err := save(filename)
			if err != nil {
				log.Println(err)
			}
		case "load":
			err := load(filename)
			if err != nil {
				log.Println(err)
			}
		case "help":
			help()
		case "exit":
			return
		}
	}
}

第4版

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

// Student struct for student info
type Student struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

var students = make(map[string]Student)

func main() {
	var line, cmd, name string
	var id int
	saved := true

	f := bufio.NewReader(os.Stdin)
	for {
		fmt.Print("> ")
		line, _ = f.ReadString('\n')
		line = strings.Replace(line, "\n", "", 1)
		_, err := fmt.Sscan(line, &cmd, &name, &id)
		// EOF for no enough space-separated values, like `list` cmd
		if err != nil && err != io.EOF {
			fmt.Println(" + parse cmd or info err:", err)
			continue
		}
		switch cmd {
		case "add":
			if addStu(name, id) {
				saved = false
			}
		case "list":
			listStu()
		case "load":
			if loadStu(name, saved) {
				saved = true
			}
		case "save":
			if saveStu(name) {
				saved = true
			}
		case "exit":
			exitStu(saved)
		case "":
			// no show usage() when ENTER
			continue
		default:
			usage()
		}
		line, cmd, name = "", "", ""
	}
}

func exitStu(s bool) {
	if s || checkYes("exit with saving stu info") {
		os.Exit(0)
	}
	return
}

func saveStu(name string) (rt bool) {
	var err error
	var fd *os.File

	// file existed and override
	if checkFileExist(name) {
		if !checkYes(fmt.Sprintf("override file %s", name)) {
			fmt.Println(" + cancel save to", name)
			return
		}
		if fd, err = os.OpenFile(name, os.O_RDWR|os.O_TRUNC, 0644); err != nil {
			fmt.Printf(" + open file error of %s\n", name)
			return
		}
		defer fd.Close()
	}
	// save to new file
	if fd, err = os.Create(name); err != nil {
		fmt.Printf(" + open new file error of %s\n", name)
		return
	}
	defer fd.Close()
	if buf, err := json.Marshal(students); err != nil {
		fmt.Println(" + marshal stu info error")
		return
	} else if _, err := fd.Write(buf); err == nil {
		fmt.Println(" + save success")
		return true
	} else {
		fmt.Println(" + save error")
		return
	}
}

// check file f exist or not
func checkFileExist(f string) bool {
	if _, err := os.Stat(f); err == nil {
		return true
	} else if os.IsNotExist(err) {
		return false
	}
	return false
}

// check yes or no for the give question
func checkYes(f string) bool {
	var s string
	for {
		fmt.Printf(" + %s, y or n? :", f)
		fmt.Scanf("%s", &s)
		if string(s[0]) == "y" || string(s[0]) == "Y" {
			return true
		} else if string(s[0]) == "n" || string(s[0]) == "N" {
			return false
		}
	}
}

func loadStu(name string, saved bool) (rt bool) {
	var err error
	var buf []byte
	if !checkFileExist(name) {
		fmt.Printf(" + file : %s not existed!\n", name)
		return
	}
	if !saved && !checkYes("clear up stu info in mem for load") {
		fmt.Println(" + give up load!")
		return
	}
	if buf, err = ioutil.ReadFile(name); err != nil {
		fmt.Printf("read from file error of %s\n", name)
		return
	}
	if err = json.Unmarshal(buf, &students); err != nil {
		fmt.Print(err)
		return
	}
	fmt.Println(" + load success")
	return true
}

func addStu(name string, id int) (rt bool) {
	if _, ok := students[name]; ok {
		fmt.Printf(" + duplicated name: %s\n", name)
		return
	}
	students[name] = Student{ID: id, Name: name}
	if _, ok := students[name]; ok {
		fmt.Println(" + add success!")
		return true
	}
	return
}

func listStu() {
	if len(students) == 0 {
		fmt.Println(" + no student info here")
		return
	}
	fmt.Println(" + Id\tName:")
	for _, val := range students {
		fmt.Printf(" + %d\t%s\n", val.ID, val.Name)
	}
}

func usage() {
	fmt.Println(" + cli usage:")
	fmt.Println(" + add name id  -- add student info")
	fmt.Println(" + list \t-- list student info")
	fmt.Println(" + load file \t-- load student from file")
	fmt.Println(" + save file \t-- save student info file")
	fmt.Println(" + exit \t-- exit the cli")
}

过程式编程

  • 函数
  • 错误异常处理
  • Go调用外部程序
  • 文件读取的多种方式

函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func add(x int, y int) int {
	return x + y
}

func main() {
	fmt.Println(add(42, 13))
}

参数类型省略

1
2
func f(i, j, k int, s, t string)
func f(i int, j int, k int, s string, t string)

多返回值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import "fmt"

func swap(x, y string) (string, string) {
	return y, x
}

func main() {
	a, b := swap("hello", "world")
	fmt.Println(a, b)
}

multi.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import "fmt"

func sum(args ...int) int {
	n := 0
	for i := 0; i < len(args); i++ {
		n += args[i]
	}
	return n
}

func main() {
	fmt.Println(sum(1, 2, 3))
	s := []int{1, 2, 3}
	fmt.Println(sum(s...))
	/*
		ta(n+1) = 2* a(n) + n
		//2 10
		// 2 6
	*/
}

命名返回值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package main

import "fmt"

func split(sum int) (x, y int) {
	x =sum / 10
	y sum % 10
	return
}

func main() {
	fmt.Println(split(17))
}

可变参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import "fmt"

func sum(args ...int) int {
	n := 0
	for i:=0, i < len(args); i++ {
		n += args[i]
	}
	return n
}

func main() {
	fmt.Println(sum(1, 2, 3))
}

递归实现斐波那契数列

递归(英語:Recursion),又译为递回,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。 递归一词还较常用于描述以自相似方法重复事物的过程。 例如,当两面镜子相互之间近似平行时,镜中嵌套的图像是以无限递归的形式出现的。 也可以理解为自我复制的过程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import "fmt"

func fib(n int) int {
	if n == 1 || n == 2 {
		return 1
	}
	return fib(n-1) + fib(n-2)
}

func main() {
	fmt.Println(fib(5))
}

return.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"fmt"
)

func print() {
	fmt.Println("hello")
}

func a(n int) int {
	fmt.Println("enter n", n)
	if n <= 1 {
		return 2
	}
	m := 2*a(n-1) + n - 1
	fmt.Println("return from a(n-1):", n)
	return m
}

func main() {
	/*
		通项公式: a(n) = 2*a(n-1) + n -1
		第一项:a(1) = 2
		求:第10项 a(10)
		a(10) = 2 * a(9) + 9 // n = 9
	*/
	fmt.Println(a(10))
}

flist.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

func main() {
	var flist []func()
	var i int
	for i = 0; i < 3; i++ {
		flist = append(flist, func() {
			fmt.Println(&i)
			fmt.Println(i)
		})
	}

	fmt.Println("i=", i)
	for _, f := range flist {
		f()
	}
}

函数类型

函数的要素

  • 函数名
  • 参数
  • 返回值
  • 如果两个函数的参数跟返回值是一样的则认为是一个类型的

函数类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"fmt"
	"log"
	"strconv"
)

func add(m, n int) int {
	return m + n
}

func sub(m, n int) int {
	return m - n
}

func main() {
	funcmap := map[string]func(int, int) int {
		"+": add,
		"-": sub,
	}
	m, _ : strconv.Atoi(os.Args[1])
	n, _ : strconv.Atoi(os.Args[3])
		
	f := funcmap[os.Args[2]]
	if f != nil {
		fmt.Println(f(m, n))
	}
}

func.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import "fmt"

func print() {
	fmt.Println("hello")
}

func print1() {
	fmt.Println("print1")
}

func func1(n int) int {
	return n + 1
}

type fstruct struct {
	Func func()
}

func main() {
	var f func()
	var flist [3]func(int) int
	var fslice []func()
	var fmap map[string]func()

	flist[0] = func1
	m := flist[0](10)

	f = print
	f()
	f = print1
	f()
	//fmt.Println(f)
}

func1.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"fmt"
	"strings"
)

func print() int {
	return 10
}
func smap(r rune) rune {
	fmt.Printf("%c\n", r)
	return r
}

func main() {
	/*
		var f func() int
		f = func() int {
			return 10
		}
	*/
	//fmt.Println(f())

	s := strings.Map(func(r rune) rune {
		return r - 32
	}, "hello")
	fmt.Println(s)
}

frame.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"strings"
)

type Student struct {
	Id   int
	Name string
}

func add(args []string) error {
	fmt.Println("call add")
	fmt.Println("args", args)
	/*
		name := args[0]
		id := args[1]
	*/
	// ....
	return nil
}

func list(args []string) error {
	return errors.New("unimplemention")
}

func main() {
	actionmap := map[string]func([]string) error{
		"add":  add,
		"list": list,
	}

	f := bufio.NewReader(os.Stdin)

	//var students map[string]Student
	for {
		fmt.Print("> ")
		line, _ := f.ReadString('\n')
		// 去除两端的空格和换行
		line = strings.TrimSpace(line)
		// 按空格分割字符串得到字符串列表
		args := strings.Fields(line)
		if len(args) == 0 {
			continue
		}
		// 获取命令和参数列表
		cmd := args[0]
		args = args[1:]

		// 获取命令函数
		actionfunc := actionmap[cmd]
		if actionfunc == nil {
			fmt.Println("bad cmd ", cmd)
			continue
		}
		err := actionfunc(args)
		if err != nil {
			fmt.Printf("execute action %s error:%s\n", cmd, err)
			continue
		}
	}
}

匿名函数和闭包

匿名函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
	"strings"
)

func toupper(s string) string {
	return strings.Map(func(r rune) rune {
		return r - ('a' - 'A')
	}, s)
}

func main() {
	fmt.Println(toupper("hello")
}

闭包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
)

func addn(n int) func(int) int {
	return func(m int) int {
		return m + n 
	}
}

func main() {
	f := addn(3)
	fmt.Println(f(2))
}

闭包的应用

iter.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
	"errors"
	"fmt"
)

var global = 1

func iter(s []int) func() (int, error) {
	var i = 0
	return func() (int, error) {
		if i >= len(s) {
			return 0, errors.New("end")
		}
		n := s[i]
		i += 1
		return n, nil
	}
}

func foo() {
	global = global + 1
	fmt.Println(global)
}

func main() {
	f := iter([]int{1, 2, 3})
	for {
		n, err := f()
		if err != nil {
			break
		}
		fmt.Println(n)
	}
	foo()
	foo()
}

error的类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"
)

func read(f *os.File) (string, error) {
	buf, err := ioutil.ReadAll(f)
	if err != nil {
		return "", err
	}
	return string(buf), nil
}

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	
	var content string
	retries := 3
	for i := 1; i <= retries; i++ {
		content, err = read(f)
		if err == nil {
			break
		}
		time.Sleep(time.Second << i)
	}
	fmt.Println(content)
}

EOF error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func read(f *os.File) (string, error) {
	var total []byte
	buf := make([]byte, 1024)
	for {
		_, err := f.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", err
		}
		total = append(total, buf[:n]...)
	}
	return string(total), nil
}

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatalf("open error:%v", err)
	}
	
	s, err := read(f)
	if err != nil {
		log.Fatalf("read err:%v", err)
	}
	fmt.Println(s)
}

panic

panic和recover

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import (
	"fmt"
)

func print() {
	var p *int
	fmt.Println(*p)
}

func main() {
	var n int
	fmt.Println(10 / n)
	print()
	
	var slice [3]int
	fmt.Println(slice[3])
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"fmt"
)

func print() {
	var p *int
	fmt.Println(*p)
}

func main() {
	defer func() {
		err := recover()
		fmt.Println(err)
	}()
	print()
	var i = 3
	var slice [3]int
	fmt.Println(slice[i])
}

panic.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import "fmt"

func print() {
	defer func() {
		err := recover()
		fmt.Println(err)
	}()

	var p *int
	fmt.Println(*p)
}
func main() {
	print()
	panic("不想执行下去了")

	var i = 3
	var slice [3]int
	fmt.Println(slice[i])
}

go执行外部命令

调用系统命令

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
	"log"
	"os/exec"
)

func main() {
	cmd := exec.Command("ls", "-l")
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(out))
}

cmd.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"bufio"
	"fmt"
	"log"
	"os/exec"
)

func main() {
	cmd := exec.Command("ls", "-l")
	out, _ := cmd.StdoutPipe()

	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}

	f := bufio.NewReader(out)
	for {
		line, err := f.ReadString('\n')
		if err != nil {
			break
		}
		fmt.Print(line)
	}
	cmd.Wait()
}

in.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import (
	"os"
	"os/exec"
)

func main() {
	cmd := exec.Command("grep", "a")
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Start()
	cmd.Wait()
}

文件读取的多种方式

读取文件几种方式

  • file.Read
  • ioutil.ReadFile
  • bufio.Scanner
  • bufio.Reader
  • io.Copy

read.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"fmt"
	"io"
	"log"
	"os"
)

func read(f *os.File) (string, error) {
	var total []byte
	buf := make([]byte, 1024)
	for {
		n, err := f.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", err
		}
		total = append(total, buf[:n]...)
	}
	return string(total), nil
}

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	s, err := read(f)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)
}

file.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"bufio"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	// 裸读取,很少使用
	buf := make([]byte, 10)
	n, err := f.Read(buf)
	buf[:n]

	// 加上buffer的读取,很高效
	r := bufio.NewReader(f)
	r.Read(buf)

	// 按行读取,按分隔符读取
	r1 := bufio.NewScanner(f)

	// 小文件一次性读取
	ioutil.ReadFile("a.txt")
	ioutil.ReadAll(f)

	// 操作类文件的神器
	io.Copy

}

copy.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
	"io"
	"log"
	"os"
)

func v1() {
	var f *os.File
	var err error
	if len(os.Args) > 1 {
		f, err = os.Open(os.Args[1])
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
	} else {
		f = os.Stdin
	}

	buf := make([]byte, 1024)
	for {
		n, err := f.Read(buf)
		if err != nil {
			return
		}
		os.Stdout.Write(buf[:n])
	}
}

func v2() {
	var f *os.File
	var err error
	if len(os.Args) > 1 {
		f, err = os.Open(os.Args[1])
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
	} else {
		f = os.Stdin
	}
	io.Copy(os.Stdout, f)
}

func main() {
	v2()
}

defer

  • 关闭文件
  • 函数返回前执行

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
)

func print() {
	defer func() {
		fmt.Println("defer")
	}()
	fmt.Println("hello")
}

func main() {
	print()
}

defer.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main

import (
	"log"
	"os"
)

func print() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
}

func main() {
	print()
}

defer文件关闭

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import (
	"log"
	"os"
)

func main() {
	f, err := os.Open("a.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	// 处理文件
}

练习:bash管道

pipe.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
	"io"
	"os"
	"os/exec"
	"strings"
	"fmt"
)

func main() {
	line := "ls | grep file"
	cmds := strings.Split(line, "|")
	s1 := strings.Fields(cmds[0])
	s2 := strings.Fields(cmds[1])

	r, w := io.Pipe()
	cmd1 := exec.Command(s1[0], s1[1:]...)
	cmd2 := exec.Command(s2[0], s2[1:]...)
	cmd1.Stdin = os.Stdin
	cmd1.Stdout = w
	cmd2.Stdin = r
	cmd2.Stdout = os.Stdout
	cmd1.Start()
	cmd2.Start()

	cmd1.Wait()
}

shell.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

func main() {
	host, _ := os.Hostname()
	prompt := fmt.Sprintf("[mulinux@%s]$ ", host)
	r := bufio.NewScanner(os.Stdin)
	//r := bufio.NewReader(os.Stdin)
	for {
		fmt.Print(prompt)
		if !r.Scan() {
			break
		}
		line := r.Text()
		// line, _ := r.ReadString('\n')
		// line = strings.TrimSpace(line)
		if len(line) == 0 {
			continue
		}
		args := strings.Fields(line)
		cmd := exec.Command(args[0], args[1:]...)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err := cmd.Run()
		if err != nil {
			fmt.Println(err)
		}
	}
}

homework

以模块化的方式重构学生管理系统

要求:

  1. 增加 updatedelete命令
  2. lesson5/binggan/frame.go为基础

完成shell的管道功能

要求:

  1. lesson5/binggan/shell.go为基础完成管道功能,如cat a.go|grep main
  2. 只用实现两个命令的管道即可