这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记.
PartI. 基本语法与变量类型
1.1 Hello World
1
package main // 在go中一个package只有一个main方法
2
3
import "fmt" // 导入标准库
4
5
func main(){
6
fmt.Println("Hello,world!")
7
}
1.2.变量
1
package main
2
3
import (
4
"fmt"
5
"math"
6
)
7
8
func main(){
9
var a = "test"
10
var b, c int = 1, 2
11
var d = true
12
var e float64
13
f := float32(e)
14
g := a + "world"
15
fmt.Println(a, b, c, d, e, f, g)
16
const s string = "constString"
17
const h = 1000000
18
fmt.Println(math.Sin(h))
19
}
go语言是一门强类型语言,每个变量都有对应的类型。
常用类型
- 整数类型:(u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr(指针),byte,rune
- 字符(串)类型:byte,rune,string(string是内置类型,可以直接使用==比较字符串)
- 浮点型:float32,float64
- 布尔型:bool
声明变量主要有两种方式:
- 通过
var 变量名 (后置类型)来声明变量,其中后置类型可省略,一般会自动推导变量的类型。 - 使用
变量 := 值的形式来声明变量。这种情况下当前变量必须未声明,否则会报错。
声明常量
go语言可以通过const关键字来声明常量,go中的常量没有确定的类型,会根据使用的上下文来自动确定类型。
Hint
go语言会检查当前变量是否被使用,如果声明后未被使用则会报错。
1.3 if else分支
1
import "fmt"
2
3
func main() {
4
if 5%2 == 0 {
5
fmt.Println("5 is even")
6
} else {
7
fmt.Println("5 is odd")
8
}
9
10
if num:=19; num>18 {
11
fmt.Println("yes")
12
}else {
13
fmt.Println("no")
14
}
15
}
- go语言中if后面不必写括号。
- 在if语句中可以定义局部变量,此时该变量仅在if语句中生效。
1.4 循环
1
import "fmt"
2
3
func main() {
4
i := 1
5
for i <= 3{
6
fmt.Println(i)
7
i++
8
}
9
for {
10
fmt.Println("hello")
11
break
12
}
13
for j := 0; j < 10; j++ {
14
fmt.Println(j)
15
}
16
}
在go语言中仅有for循环,不支持while、do while循环。最简单的for循环就是在后面什么都不加,默认为死循环,需要通过break去进行中止。其他的类似于其他语言,唯一的区别就是语句不需要加括号,直接写即可。
1.5 switch
1
import (
2
"fmt"
3
"time"
4
)
5
6
func main() {
7
i := 1
8
switch i {
9
case 1:
10
fmt.Println("111")
11
default:
12
fmt.Println("other")
13
}
14
t := time.Now()
15
switch {
16
case t.Hour() > 12 :
17
fmt.Println("过了12点了")
18
default:
19
fmt.Println("还没过12点")
20
}
21
}
在go语言中switch分支功能强大。switch case里面不用加break也能自动的结束。另外,siwtch后面可以不加其他变量,然后再case中写条件分支来判断,比写多个if else会清晰很多。
1.6 数组
1
import "fmt"
2
3
func main() {
4
var a [5]int
5
a[1] = 20
6
fmt.Println(a[1], len(a))
7
8
b := [5]int{1,2,3,4,5} // 数组初始化赋值
9
fmt.Println(b) // 打印的就是数组内容而非数组地址
10
11
var darr [3][3] int
12
for i := 0; i < 3; i++{
13
for j := 0; j < 3; j++{
14
darr[i][j] = i + j
15
}
16
}
17
fmt.Println(darr)
18
}
1
20 5
2
[1 2 3 4 5]
3
[[0 1 2] [1 2 3] [2 3 4]]
不过在真实业务中我们使用切片较多,不常使用数组。
1.7 切片
1
import "fmt"
2
3
func main() {
4
s := make([]string, 5)
5
s[0] = "a"
6
s[1] = "b"
7
s[2] = "c"
8
s[3] = "d"
9
s[4] = "e"
10
fmt.Println(s[3], len(s))
11
12
s = append(s, "f")
13
s = append(s, "g", "h")// 变长参数
14
fmt.Println(s, len(s))
15
16
c := make([]string, len(s))
17
copy(c, s) // target, src
18
fmt.Println(c)
19
20
fmt.Println(s[2:5])
21
fmt.Println(s[:5])
22
fmt.Println(s[2:])
23
fmt.Println(s[:])
24
}
1
d 5
2
[a b c d e f g h] 8
3
[a b c d e f g h]
4
[c d e]
5
[a b c d e]
6
[c d e f g h]
7
[a b c d e f g h]
slice不同于数组,可以任意更改长度,我们通过make(type, len)来创建一个切片。
slice可以像数组一样去取值,也可以通过append(slice, params…)来追加元素。注意这里的params是可变参数列表,可以追加多个,如果容量不够的话会扩容并返回新的slice。
slice具有类似于Python的切片操作,比如可以通过[start:end]取出指定位置的元素[start, end)。但是这里不同于Python的是不支持负数索引。
1.8 map
1
import "fmt"
2
3
func main() {
4
m := make(map[string]int) // key: string value:int
5
m["a"] = 10
6
m["b"] = 20
7
fmt.Println(m)
8
fmt.Println(len(m))
9
r, ok := m["a"]
10
fmt.Println(r, ok)
11
//r, ok := m["e"]
12
//fmt.Println(r, ok)
13
delete(m, "a")
14
fmt.Println(m)
15
}
1
map[a:10 b:20]
2
2
3
10 true
4
// 0 false
5
map[b:20]
map是实际使用过程中最频繁用到的数据结构。我们可以通过make来创建一个空map,这里的map[string]int中string为key的类型,int为value的类型。我们可以通过类似数组取值的方式赋值map(不同于Java的map.put方法)。另外,在取map对应key值的时候可以获取到其bool元素命名为ok,标识着是否成功取到该元素(true or false)
go语言中的map是完全无序的,遍历时候不会按照字母顺序/插入顺序,而是随机顺序。
1.9 range
1
import "fmt"
2
3
func main() {
4
nums := []int{2, 3, 4}
5
sum := 0
6
for i, num := range nums{
7
sum += num
8
if num == 2 {
9
fmt.Println("index:", i, "num:", num) //index: 0 num: 2
10
}
11
}
12
fmt.Println(sum) // 9
13
14
m := map[string]string{"a": "A", "b": "B"}
15
for k, v := range m {
16
fmt.Println(k, v) // a A b B
17
}
18
for k := range m {
19
fmt.Println(k) // a b
20
}
21
22
}
对于一个slice和map,我们可以通过range进行快速遍历。
range遍历时对于数组可以返回index和对应位置的值(如果不需要索引一般使用_来忽略),对于slice则返回key和value。
PartII. 方法、结构体与常见操作
2.1 方法
1
import "fmt"
2
3
func add(a int, b int) int {
4
return a + b
5
}
6
7
func add2(a, b int) int {
8
return a + b
9
}
10
11
func exists(m map[string]string, k string) (v string, ok bool){
12
v, ok = m[k]
13
return v, ok
14
}
15
16
func main() {
17
res := add(1, 2)
18
fmt.Println(res) // 3
19
20
v, ok := exists(map[string]string{"a":"A"}, "a")
21
fmt.Println(v, ok) // A true
22
}
go语言中变量类型后置,返回值类型也后置。在go函数中可以有多个返回值。
2.2 指针
1
import "fmt"
2
3
func add2(n int){
4
n += 2
5
}
6
7
func add(n *int){
8
*n += 2
9
}
10
11
func main() {
12
n := 5
13
add2(n)
14
fmt.Println(n) // 5
15
add(&n) // 注意是传地址,因为参数是指针
16
fmt.Println(n) // 7
17
}
go语言也支持指针,但是相比于C/C++中的指针支持的操作很有限。传指针的主要用途就是对传入参数进行修改。
2.3 结构体
1
import "fmt"
2
3
type user struct{
4
name string
5
password string
6
}
7
8
func main() {
9
a := user{name: "zhangsan", password: "123456"}
10
b := user{"zhangsan", "123456"}
11
c := user{name:"wang"}
12
c.password = "1234"
13
d := user{}
14
fmt.Println(a, b, c, d) // {zhangsan 123456} {zhangsan 123456} {wang 1234} { }
15
}
在go语言中支持定义结构体,结构体可以通过{}进行直接赋值,也可以通过.获取对应的成员变量进行赋值。
结构体也支持指针,能够实现对结构体内部的修改。
2.4 结构体方法
1
import "fmt"
2
3
type user struct{
4
name string
5
password string
6
}
7
8
func (u user) checkPassWord(password string) bool {
9
return u.password == password
10
}
11
12
func (u *user) resetPassWOrd(password string) {
13
u.password = password
14
}
15
16
func main() {
17
a := user{name: "zhangsan", password: "123456"}
18
fmt.Println(a.checkPassWord("123456")) // true
19
a.resetPassWOrd("123")
20
fmt.Println(a) //{zhangsan 123}
21
}
可以通过在方法名前指定类型来定义结构体方法,注意这里传参也可以传其本身或者是指针。传本身实际是传一个拷贝,无法对结构体内部进行修改。
2.5 错误处理
1
import (
2
"errors"
3
"fmt"
4
)
5
6
type user struct{
7
name string
8
password string
9
}
10
11
func findUser(users []user, name string) (v *user, err error){
12
for _, u := range users {
13
if u.name == name {
14
return &u, nil
15
}
16
}
17
return nil, errors.New("not found")
18
}
19
20
func main() {
21
u, err := findUser([]user{{"zhangsan", "123456"}}, "zhangsan")
22
if err != nil {
23
fmt.Println(err)
24
return
25
}
26
fmt.Println(u.name)
27
28
if u, err := findUser([]user{{"zhangsan", "123456"}}, "zs"); err != nil{
29
fmt.Println(err)
30
return
31
}else{
32
fmt.Println(u.name)
33
}
34
}
在go语言中一般用一个单独的返回值来传递错误信息。
2.6 字符串操作
1
import (
2
"fmt"
3
"strings"
4
)
5
6
func main() {
7
a := "hello"
8
fmt.Println(strings.Contains(a, "ll")) // true
9
fmt.Println(strings.Count(a, "l")) // 2
10
fmt.Println(strings.HasPrefix(a, "he")) // true
11
fmt.Println(strings.Index(a, "ll")) // 2
12
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
13
fmt.Println(strings.Repeat(a, 2)) // hellohello
14
fmt.Println(strings.Replace(a, "e", "E", - 1)) // hEllo
15
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
16
fmt.Println(len("你好")) // 6
17
}
使用strings工具类的方法即可,类似于Java中工具类,不过Java中String类操作是其成员方法。
2.7 JSON处理
1
import (
2
"encoding/json"
3
"fmt"
4
)
5
6
type userInfo struct{
7
Name string
8
Age int
9
Hobby []string
10
}
11
12
func main() {
13
a := userInfo{"zhangsan", 19, []string{"golang","java"}}
14
buf, err := json.Marshal(a)
15
if err != nil {
16
panic(err)
17
}
18
fmt.Println(buf) // [123 34 78 ....]
19
fmt.Println(string(buf)) // {"Name":"zhangsan","Age":19,"Hobby":["golang","java"]}
20
21
var temp userInfo
22
err = json.Unmarshal(buf, &temp)
23
if err != nil{
24
panic(err)
25
}
26
fmt.Printf("%#v\n", temp)
27
}
go语言中的JSON操作比较简单,对于一个已有的结构体,只要其字段首字母是大写(公开字段),那么这个结构体就能够用JSON.marshal进行序列化变成JSON字符串,也可以通过JSON.Unmarshal方法进行反序列化。如果对序列化的风格结果有要求,可以在结构体中使用json tag来改变json序列化的字段名。
2.8 时间处理
1
import (
2
"fmt"
3
"time"
4
)
5
6
func main() {
7
now := time.Now()
8
fmt.Println(now) // 2022-05-08 14:16:21.865038 +0800 CST m=+0.000059543
9
t := time.Date(2022, 5, 8, 13,45,23,0,time.UTC)
10
fmt.Println(t) // 2022-05-08 13:45:23 +0000 UTC
11
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 May 8 13 45
12
fmt.Println(t.Format("2006-01-02 15:04:05")) // go日期初始化定义的时间,不能更改 2022-05-08 13:45:23
13
fmt.Println(t.Format("06.01.02 15-04-05")) // 22.05.08 13-45-23
14
diff := now.Sub(t)
15
fmt.Println(diff.Hours(), diff.Minutes()) //-7.411009986944444 -444.66059921666664
16
fmt.Println(now.Unix()) // 1651990921 获取时间戳
17
}
go可通过time的一序列方法获取当前时间,对时间进行格式化,对时间进行作差等。
PartIII. 实战
3.1 猜谜游戏
1
import (
2
"bufio"
3
"fmt"
4
"math/rand"
5
"os"
6
"strconv"
7
"strings"
8
"time"
9
)
10
11
func main(){
12
maxNum := 100
13
rand.Seed(time.Now().UnixNano()) // 使用时间戳初始化随机种子
14
secretNumber := rand.Intn(maxNum)
15
//fmt.Println(secretNumber)
16
17
fmt.Println("Please input your guess")
18
reader := bufio.NewReader(os.Stdin)
19
20
for {
21
input, err := reader.ReadString('\n')
22
if err != nil {
23
fmt.Println("An error occurred while reading input. Please try again", err)
24
continue
25
}
26
input = strings.TrimSuffix(input, "\n")
27
28
guess, err := strconv.Atoi(input)
29
if err != nil {
30
fmt.Println("Invalid input. Please enter an integer value!")
31
continue
32
}
33
fmt.Println("Your guess is", guess)
34
if guess > secretNumber {
35
fmt.Println("Your guess is bigger than the secret number. Please try again")
36
} else if guess < secretNumber {
37
fmt.Println("Your guess is smaller than the secret number. Please try again")
38
} else {
39
fmt.Println("Correct, you Legend!")
40
break
41
}
42
}
43
}
44
经典实验题emm,主要了解语言特性,这里注意输入是通过bufio.NewReader(os.Stdin)获取输入流。
3.2 在线字典
1
package main
2
3
import (
4
"bufio"
5
"bytes"
6
"encoding/json"
7
"fmt"
8
"io/ioutil"
9
"log"
10
"net/http"
11
"os"
12
"strings"
13
)
14
15
type DictRequest struct {
16
TransType string `json:"trans_type"`
17
Source string `json:"source"`
18
UserID string `json:"user_id"`
19
}
20
21
type DictResponse struct {
22
Rc int `json:"rc"`
23
Wiki struct {
24
KnownInLaguages int `json:"known_in_laguages"`
25
Description struct {
26
Source string `json:"source"`
27
Target interface{} `json:"target"`
28
} `json:"description"`
29
ID string `json:"id"`
30
Item struct {
31
Source string `json:"source"`
32
Target string `json:"target"`
33
} `json:"item"`
34
ImageURL string `json:"image_url"`
35
IsSubject string `json:"is_subject"`
36
Sitelink string `json:"sitelink"`
37
} `json:"wiki"`
38
Dictionary struct {
39
Prons struct {
40
EnUs string `json:"en-us"`
41
En string `json:"en"`
42
} `json:"prons"`
43
Explanations []string `json:"explanations"`
44
Synonym []string `json:"synonym"`
45
Antonym []string `json:"antonym"`
46
WqxExample [][]string `json:"wqx_example"`
47
Entry string `json:"entry"`
48
Type string `json:"type"`
49
Related []interface{} `json:"related"`
50
Source string `json:"source"`
51
} `json:"dictionary"`
52
}
53
54
func query(word string) {
55
client := &http.Client{}
56
//var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
57
request := DictRequest{"en2zh", word, ""}
58
buf, err := json.Marshal(request)
59
if err != nil{
60
log.Fatal(err)
61
}
62
var data = bytes.NewReader(buf)
63
64
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
65
if err != nil {
66
log.Fatal(err)
67
}
68
req.Header.Set("Accept", "application/json, text/plain, */*")
69
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
70
req.Header.Set("Connection", "keep-alive")
71
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
72
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
73
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
74
req.Header.Set("Sec-Fetch-Dest", "empty")
75
req.Header.Set("Sec-Fetch-Mode", "cors")
76
req.Header.Set("Sec-Fetch-Site", "cross-site")
77
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36")
78
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
79
req.Header.Set("app-name", "xy")
80
req.Header.Set("os-type", "web")
81
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
82
req.Header.Set("sec-ch-ua-mobile", "?0")
83
req.Header.Set("sec-ch-ua-platform", `"macOS"`)
84
resp, err := client.Do(req)
85
if err != nil {
86
log.Fatal(err)
87
}
88
defer resp.Body.Close()
89
bodyText, err := ioutil.ReadAll(resp.Body)
90
if err != nil {
91
log.Fatal(err)
92
}
93
if resp.StatusCode != 200 {
94
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
95
}
96
//fmt.Printf("%s\n", bodyText)
97
var dictResponse DictResponse
98
err = json.Unmarshal(bodyText, &dictResponse)
99
if err != nil{
100
log.Fatal(err)
101
}
102
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
103
for _, item := range dictResponse.Dictionary.Explanations {
104
fmt.Println(item)
105
}
106
}
107
108
func main() {
109
reader := bufio.NewReader(os.Stdin)
110
word, err := reader.ReadString('\n')
111
if err != nil {
112
fmt.Println(err)
113
return
114
}
115
word = strings.TrimSuffix(word, "\n")
116
query(word)
117
效果:
\