【青训营笔记】- Go 语言基础与语法实战案例

106 阅读4分钟

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

前言

今天是第五届青训营开营后的第一节正式课,本次青训营的推荐语言是Go,因此策划人和讲师们细心地为像我这样没有Go语言基础的人专门开设了一节语法讲解的课程,十分贴心,并且在语法后由简到难为我们设计了三个语法实战案例,讲解了具体的代码流程。以下是本次课程的学习笔记以及一些个人的思考。

Go语言语法基础讲解

一、本堂课重点内容:

  • Go 语言简介
  • Go 语言开发入门,包括开发环境配置、基础语法、标准库
  • Go 实战,包括三个实战项目

二、详细知识点介绍:

Go语言特点

  1. 高性能、高并发:自带高并发支持,做了goroutine的优化提高并发效率
  2. 语法简单、学习曲线平缓:C/C++语法的简化,C是程序员入门语言,go语法简化,上手快
  3. 丰富的标准库:标准库强大且完备,不需要引入第三方库,稳定且快
  4. 完善的工具链:代码管理、代码测试、文档等学习开发工具
  5. 静态链接:编译后静态链接,生成可执行文件,部署转移方便
  6. 快速编译:快速的编译速度使代码开发速度加快,随写随编译
  7. 跨平台:跨平台使得go的应用平台广,前景广
  8. 垃圾回收:不需要管理内存,进一步释放了程序员的压力
  • 个人感悟:Go这么多的特点使得Go在这些年逐渐火爆起来,特别是简单且性能好,部署简单、依赖简化这些非常重要的特点都是Go崛起的非常重要的原因!!这些特点具有很大的优势!

Go 语言开发入门

开发环境配置

VSCode 和 GoLand 两种主流的IDE,需要安装GoLand环境 1 2 3

  • 个人感悟:其实与我熟悉的Java语言的一致的,下载编译环境,配置环境变量等

基础语法

HelloWorld

package main

import (
   "fmt"
)

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

变量类型

  • string : 可以加号和等号拼接
  • int
  • float
  • bool

变量声明

  • var 变量名 = 值
  • var 变量名 变量类型
  • 变量名 := 值

常量声明

  • const 变量名 类型 = 值

  • 常量不需要类型,自动上下文

  • 个人感悟:变量的声明与我熟悉的语言不太一致,要注意辨识,但也非常方便,可能类型自动匹配

if else

package main

import "fmt"

func main() {

	if 7%2 == 0 {
		fmt.Println("7 is even")
	} else {
		fmt.Println("7 is odd")
	}

	if 8%4 == 0 {
		fmt.Println("8 is divisible by 4")
	}

	if num := 9; num < 0 {
		fmt.Println(num, "is negative")
	} else if num < 10 {
		fmt.Println(num, "has 1 digit")
	} else {
		fmt.Println(num, "has multiple digits")
	}
}

  • 判断不用括号,必须添加花括号

循环

  • 只有for循环
  • for 加花括号为死循环
  • for 加常见的三段式,不需要括号
  • 可以用continue和break

switch

  • 判断对象不需要括号
  • 不需要break
  • 支持字符串、结构体等多种类型
  • 替换ifelse代码更加清晰

数组 分为固定数组和动态数组slice切片,一般只用动态数组切片

  • 创建:make([]int,容量)
  • 添加:append ,记得重新赋值变量
  • len(arr)看长度,cap(arr)看容量
  • copy(dst,src)复制内容
  • 切片操作:arr[2:5]:取出[2,5)之间的数据

map

  • 形式:map[key类型]value类型
  • 创建:make(map[key类型]value类型,容量)
  • 添加:m[key] = value
  • 删除:delete(m,key)

range

  • 快速遍历很多类型
  • 对于数组,返回索引和值
  • 对于map,每次返回key和value

函数

  • 形式: func 函数名(形参名 形参类型,形参名 形参类型...) (返回名 返回类型,返回名 返回类型...)

指针

  • 支持指针,同C,&取地址,*取值

结构体

  • 定义
type user struct {
	name     string
	password string
}
  • 创建与访问结构体
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
  • 可以作为函数参数类型,同样是传值,有时传指针减少复制开销

结构体方法

  • func (结构体变量名 结构体类型)函数名(形参名 形参类型,形参名 形参类型...) (返回名 返回类型,返回名 返回类型...)
  • 类似面向对象的类成员方法的作用,可以实现面向对象封装特性

错误处理

  • error类型是错误类型,替代了java语言的异常机制
  • errors.New(“错误信息”)
  • 结合多返回值类型可以做到错误判断和处理,错误返回error,没有返回nil

字符串操作

  • 在strings包中
  • Contains
  • Count
  • HasPrefix
  • HasSUffix
  • Index
  • Join
  • Repeat
  • Replace
  • Split
  • ToLower
  • ToUpper
  • len:获取字符串占用的字节数,如果是ASCII则是字符串长度一致

字符串格式化

  • fmt包中
  • println:换行输出
  • printf:格式输出
  • %v:不需要根据输出的类型用其他的字母,%v可以自动判断
  • %+v:更加详细的信息
  • %#v: 进一步详细的信息
  • %.2f:类似C语言的格式化输出,其他也一样

JSON处理

  • json包能处理json格式的转换和解析
  • 只要保证带解析和转换的结构体的成员名的第一个字母为大写则表示对外包可访问
  • json.Marshal():将结构体序列化成字符串的字节数组,string(buf)转成字符串
  • json.Unmarshal(buf,结构体变量指针):反序列成一个结构体赋值给结构体变量
  • 加名为''josn'的tag标签可以改变序列化的名字

时间处理

  • time.Now():获取当前时间的结构体
  • time.Date(年,月,日,时,分,秒,毫秒):构造带时区的时间
  • 结构体对象.Year()...获取具体对应的值
  • 结构体对象.Sub(time)...时间进行相对应的比较操作返回一个时间差
  • t.Format("2006-01-02 15:04:05"):返回一个格式化的字符串
  • time.Parse("2006-01-02 15:04:05"):解析特定格式的字符串到时间结构体
  • time.Now().Unix():获取时间戳

数字解析

  • strconv.ParseFloat("",字节数)
  • strconv.ParseInt("",进制数,字节数)
  • strconv.Atoi(""):十进制字符串转成数字
  • strconv.Itoa():数组字符串
  • 这些都会返回错误error结构体

进程对象

  • os.Args()返回一个字符串对象,内容为运行的信息,包括可执行文件的内容和传入的参数
  • os.Getenv和Setenv:获取和写入环境变量
  • exec.Command("命令","IP","文件位置")。CombinedOutput():执行命令并输入输出

标准库

  • fmt:格式化输出包
  • math/rand:随机数包
  • time:时间处理包
  • bufio:缓冲IO包
  • os:操作系统有关的包
  • strconv:字符串转换处理包
  • strings:字符串处理包
  • net/http :http有关的包
  • json:生成json字符串和解析字符串为结构体

三、实践练习例子:

  • 猜谜游戏 复习了变量,循环,函数控制处理,错误处理等
  1. 用math/rand包生成随机数,记得设置随机数种子保证伪随机
  2. 用标准输入读取用户输入
  3. 实现逻辑判断
  4. 实现游戏循环
package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
)

func main() {
	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
		}
	}
}

  • 命令行词典
  1. 在线抓包获得接口信息和传入参数
  2. 代码生成一个Http请求包
  3. 生成requestbody
  4. 解析response body,定义结构体,结合json
  5. 打印结构
  6. 完善代码
代码略
  • SOCKS5代理服务器

    • SOCKS5原理介绍
    • TCP echo server的实现
    • auth函数来处理SOCKS5鉴权阶段
    • 请求阶段,字节解析和讲解以及connect函数的实现
    • relay阶段来建立连接 较为复杂,详情参考代码

四、课后个人总结:

  • 总的来说,Go语言的基础语法与C/C++类型,做了一些简化,总体来说熟悉一下应该能够对Go语言的基础语法有一个大概的认识,其中想if-else 、 while 、 switch 、结构体等基本一致,没有太大的区别。
  • go语言的一个特点就是他的函数,它能支持多返回值,使得编码的灵活性大大提高了,它的格式也与一般的语法不太一样,有了一点区别,需要稍加注意。
  • 最重要的内容是对标准库的熟悉和使用,文章一开头就说过了,强大的标准库是Go语言的一大特点,它有很完备的标准库,要懂得去使用文档去查找不熟悉的标准库和它的哟用法,要有这种能力才能快速上手Go语言!