Go语言基础| 青训营笔记

375 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

Go语言基础

先说一下自己这节课的感想。基础知识过的很快,对于新手来说还是比较难的的,基础语法20分钟就讲完了。后面的例子第三个代理案例还是比较有难度的,但是都比较有趣。也认识了很多两个小工具,一个curl转go语言,另一个json格式转go结构体。

入门笔记

hello

知识点:fmt.Println("hello world")打印功能

var

//变量初始化方法:
//利用var自动推导
var a = "initial"
//利用var显示推导
var b, c int = 1, 2
//利用:=来初始化
g := "foo"

然后go的常见变量类型包括字符串、整型、浮点型、布尔值等

如果想用常量,只需要把var改成const

const s string = "constant"

if

//if的格式为
if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
}

相比其他语言,特别的是,布尔表达式外面没有小括号

for

//for的格式类似于C语言
for 初始化语句; 条件语句; post语句{
    循环体语句
}
//或者省略初始化和post语句只剩下中间的条件语句(分号也可以省略)
for 条件语句{
    循环体语句
}
for i <= 3 {
	fmt.Println(i)
	i = i + 1
}

switch

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

相比其他其他语言就是我们不需要手动去break,防止依次执行下面语句。

Array

//声明数组
var 变量名 [大小] 变量类型
//数组初始化
b := [5]int{1, 2, 3, 4, 5}
//如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
b := [...]int{1, 2, 3, 4, 5}

一般开发不用数组,用切片,因为数组大小固定。

slice

//声明切片
s := make([]string, 3)
//切片初始化
good := []string{"g", "o", "o", "d"}
//切片赋值
s[0] = "a" //索引下标赋值
s = append(s, "d") //append追加

map

//map声明
m := make(map[string]int) //string代表key类型,int代表value类型
//put使用
m["one"] = 1
//get使用
r, ok := m["unknow"]
//delete使用
delete(m, "one")
//map初始化
m2 := map[string]int{"one": 1, "two": 2}

range

range一般用在for循环里面对数组、切片和集合等进行迭代

nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
	sum += num
	if num == 2 {
		fmt.Println("index:", i, "num:", num) // index: 0 num: 2
	}
}

func

func就是定义函数,但是特点是,返回值可以有多个

func 函数名(参数列表) (返回值列表) { 
    // 函数体
}
func add(a, b int) int {
	return a + b
}

point

point指针,跟C语言用法差不多

func add2(n int) {
	n += 2
}

func add2ptr(n *int) {
	*n += 2
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n) // 5
	add2ptr(&n)
	fmt.Println(n) // 7
}

struct

go语言没有类,只有结构体

//定义结构体
type user struct {
	name     string
	password string
}
//结构体初始化
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}

然后因为结构体没有构造函数,但是可以有内部函数,也叫结构体方法

type user struct {
	name     string
	password string
}
func (u user) checkPassword(password string) bool {
	return u.password == password
}
//主要是在func和方法名字前中间加上(变量名 结构体名)

error

Go语言中引入 error 接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含 error。error 处理过程类似于C语言中的错误码,可逐层返回,直到被处理。 主要每层方法都可以抛出error,然后可以用简单的if else就可以处理错误,不像java的try catch。

string

strings包里面有非常多对字符串操作的方法比如:

是否包含,计算某个字符出现的个数,是否有前缀字母,是否有后缀字母,目标字母的索引,连接字符,重复字母,替换字符,转大小写。

a := "hello"
fmt.Println(strings.Contains(a, "ll"))                // true
fmt.Println(strings.Count(a, "l"))                    // 2
fmt.Println(strings.HasPrefix(a, "he"))               // true
fmt.Println(strings.HasSuffix(a, "llo"))              // true
fmt.Println(strings.Index(a, "ll"))                   // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2))                     // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
fmt.Println(strings.ToLower(a))                       // hello
fmt.Println(strings.ToUpper(a))                       // HELLO
fmt.Println(len(a))                                   // 5

fmt

fmt主要实现格式化输出

Println就是输出一行空一行 Printf可以理解为c语言的printf,有占位符的。

//Print函数直接输出内容
//Printf函数支持格式化输出字符串
//Println函数会在输出内容的结尾添加一个换行符
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p)    // {1 2}
fmt.Printf("s=%v\n", s)  // s=hello
fmt.Printf("n=%v\n", n)  // n=123
fmt.Printf("p=%v\n", p)  // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f)          // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14

占位符网上搜一下就会有了

json

//只要保证结构体的字段名首字母大写,我们就可以用json.Marshal进行序列化
type userInfo struct {
	Name  string
	Age   int `json:"age"`
	Hobby []string
}
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a)
if err != nil {
	panic(err)
}
fmt.Println(buf)         // [123 34 78 97...]
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
//然后也可以用json.Unmarshal进行反序列化
var b userInfo
err = json.Unmarshal(buf, &b)

time

now := time.Now() //获取当前时间
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)//时间初始化
fmt.Println(t)                                                  // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05"))                    // 2022-03-27 01:25:36
diff := t2.Sub(t)//减时间
fmt.Println(diff)                           // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900(换算成分钟,换算成秒)
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
	panic(err)
}
now.Unix() //获取时间戳

在格式化的时候,一定要遵从"2006-01-02 15:04:05"

strconv

strconv提供了各种各样的转换数据方法

f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax

env

fmt.Println(os.Args)           // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
	panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1       localhost
//获取进程参数,环境变量等

实战案例

猜谜游戏

maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
// fmt.Println("The secret number is ", secretNumber)

fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
for {
	input, err := reader.ReadString('\n')
	if err != nil {
		fmt.Println("An error occured while reading input. Please try again", err)
		continue
	}
	input = strings.Trim(input, "\r\n")

	guess, err := strconv.Atoi(input)
	if err != nil {
		fmt.Println("Invalid input. Please enter an integer value")
		continue
	}
	fmt.Println("You guess is", guess)
	if guess > secretNumber {
		fmt.Println("Your guess is bigger than the secret number. Please try again")
	} else if guess < secretNumber {
		fmt.Println("Your guess is smaller than the secret number. Please try again")
	} else {
		fmt.Println("Correct, you Legend!")
		break
	}
}

这个案例难度不大,主要是运用了

rand.Seed()随机种子

rand.Intn()获取随机数

bufio.NewReader(os.Stdin)获取用户输入

strconv.Atoi()字符串转数字

其他就是包含了for循环、if判断、标准输出

命令行字典

type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
	UserID    string `json:"user_id"`
}

type DictResponse struct {
	Rc   int `json:"rc"`
	Wiki struct {
		KnownInLaguages int `json:"known_in_laguages"`
		Description     struct {
			Source string      `json:"source"`
			Target interface{} `json:"target"`
		} `json:"description"`
		ID   string `json:"id"`
		Item struct {
			Source string `json:"source"`
			Target string `json:"target"`
		} `json:"item"`
		ImageURL  string `json:"image_url"`
		IsSubject string `json:"is_subject"`
		Sitelink  string `json:"sitelink"`
	} `json:"wiki"`
	Dictionary struct {
		Prons struct {
			EnUs string `json:"en-us"`
			En   string `json:"en"`
		} `json:"prons"`
		Explanations []string      `json:"explanations"`
		Synonym      []string      `json:"synonym"`
		Antonym      []string      `json:"antonym"`
		WqxExample   [][]string    `json:"wqx_example"`
		Entry        string        `json:"entry"`
		Type         string        `json:"type"`
		Related      []interface{} `json:"related"`
		Source       string        `json:"source"`
	} `json:"dictionary"`
}

func query(word string) {
	client := &http.Client{}
	request := DictRequest{TransType: "en2zh", Source: word}
	buf, err := json.Marshal(request)
	if err != nil {
		log.Fatal(err)
	}
	var data = bytes.NewReader(buf)
	req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("DNT", "1")
	req.Header.Set("os-version", "")
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
	req.Header.Set("app-name", "xy")
	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("device-id", "")
	req.Header.Set("os-type", "web")
	req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
	req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("Sec-Fetch-Site", "cross-site")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
	req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != 200 {
		log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
	}
	var dictResponse DictResponse
	err = json.Unmarshal(bodyText, &dictResponse)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
	for _, item := range dictResponse.Dictionary.Explanations {
		fmt.Println(item)
	}
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
		`)
		os.Exit(1)
	}
	word := os.Args[1]
	query(word)
}

真狠啊,第二个案例就是网络抓包,要知道,基础才学完20分钟。。。

主要就是包含请求结构体和相应结构体,不过看视频确实有很多工具可以使用,非常方便。我也是第一次知道网络里面可以直接复制请求为curl指令。然后再借助工具转换成语言。

client := &http.Client{} 
request := DictRequest{TransType: "en2zh", Source: word} 
buf, err := json.Marshal(request) 
if err != nil { 
    log.Fatal(err) 
} 
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data) //创建请求
if err != nil { 
    log.Fatal(err) 
}
//然后就是一系列请求头设置
...
resp, err := client.Do(req) //发起请求
defer resp.Body.Close() //延时关闭
bodyText, err := ioutil.ReadAll(resp.Body) //读取响应

一旦读取到响应我们就可以反序列化成json结构体了。 之后也是运用到了os.Args读取参数

代理服务器

说实话这个没怎么听懂,流程大概懂了。就没什么好记的了,这些协议代号好多不懂,有空再去研究这个例子。

总结

今天的课比较快的,但是对于进阶班同学我觉得难度还是可以的,但是我必须吐槽一下第三个案例,是我太弱了还是什么,那个协议理解的真的很抽象,而且有一些基础知识没讲到,比如接口的使用,但是案例中是使用到的。