go语言基础与项目实践|青训营笔记
这是我参与「第五届青训营」笔记创作活动的第一天
特点
- 垃圾回收机制: 类似java,可以忽略程序执行过程中内存空间的管理
- 强类型语言:如整数,浮点,字符串,布尔等
基础语法
- package
- 首行确定入口文件
- 单文件的代码必须用package main,否则会出现报错
- eg: package main,但是如果不是作为主函数执行,可以用其他的
- import 导入包
- 格式:
import{包1,包2,包3....} - fmt:输入输出相关库
- encoding/json :json相关操作的文件 如:json.Marshal()函数
- encoding/xml -等等
- 格式:
- 主函数
func main(){程序执行内容}
- 变量
- 强类型语言
- 常见类型:整数,浮点,布尔,字符串,变量特征基本和C++和java类似
- 变量声明(主要区别)
- var 变量名=值
eg:var a=1; - var 变量名 变量类型 = 值
eg: var a int =3; var a string="123" - var 变量名:=变量类型 值
eg: f:=int 12
- var 变量名=值
- 常见的语句类型(只记录常见类型)
- 分支语句
- if 语句
-格式
if 条件 { 执行1 执行2 }- 注意
- 条件不用加括号
- ‘{’ 必须和条件在同一行,不可以换行
- 注意
- switch 语句
switch a{ case 条件1: 执行1 //不用再加break case 条件2: 执行2 case 条件3:执行3 default: 条件4 }- 注意
- 条件不用加括号
- ‘{’ 必须和条件在同一行,不可以换行
- 与C的不同,执行语句后不用加break打断,即若同时满足1只执行1;
- 注意
- if 语句
-格式
- 循环语句(go中只有for循环)
- for循环
- 常见语句
for {//for后不加条件,类似与死循环 循环体 } //类似C的for循环,注意:条件不加括号,“{”的位置。 for i:=1;i<9;i++{ 循环体 }
- for循环
- 分支语句
- 常见数据结构
- 数组(array)
- 数组的定义:
eg:var a[5]int - 其余和C中数组类似,长度固定不常用。
- 数组的定义:
- 切片(slice)
- 类似变长数组(可扩容)
- 切片定义:
s:=make([]string,5)//初始容量为3的字符切片 var s= make([] int, 4)//初始容量为4的切片- 切片的赋值和相关操作类似数组
- 特殊
s=append(s,值) append必须赋值回给s c:=make([]string,2) copy(c,s) //将s中的内容复制到C,到那时由于len(c)<len(s)所以,值赋值s的前两个元素 s[2:5]取s index=2的元素到index=5的元素(不包含第五个)的部分 - Map hash/字典
- 类似字典和hash表的键值对
- 定义
s:=make(map[string(键的类型)]int(值的类型)) var s= make(map[string(键的类型)]- 操作类似python字典
//m是一个初始为空的字典 //添加key1-value1,key2-value2的键值对 m['key1']=value1 m['key2']=value2 delete(m,key1)删除m中key1-value1的键值对 //map是完全乱序的 thevalue,ok=m['one']//获取key=one的值,若存在这样的键值对,ok=nil,thevalue=value,若不存在这样的键值对则 ok!=nil而是等于err等
- 数组(array)
- 遍历( range)
- range遍历数组
//nums[13,14] for i,num :=range nums{ fmt.println("index",i,"value",num) //结果是 index 0 value 13 // index 1 value 14 i:index; num:值 } //如果只想取num的值可以用 '_'替代i,即可不取返回的index - range遍历map
e := make(map[string]int) e["one"] = 1 e["two"] = 2 for key, _ := range e { //只取key值 fmt.Println("key", key) } //取key,value的值 for key,value := range e{ fmt.Println("key", key,"value",value) }
- range遍历数组
- 函数
- 定义 func 函数名(参数){函数体}
func 函数名(类型 parm1,类型 parm2) { 函数体 }
- 定义 func 函数名(参数){函数体}
- 指针
- 基本与C指针相同,&取地址,*取指针指向的值
- 结构体
- 定义与C类似,但是变量名在前,类型在后
type 结构体类型名 struct{ 变量名 类型 变量名 类型 .... } eg: type student struct{ id int name string }- 声明结构体变量 eg:
stu1:=student{id:1,name:"Tom"}//若未全部指定,未指定的值取空值 - 结构体方法(类似类成员函数)
定义 func (形参 结构体名) 函数名(参数列表)(返回类型,可以有多个返回值)不填默认为空{函数体} eg: func (s *student) setinfo(int id, int name) { s.id=id s.name=name } //调用 var stu2 student stu.setinfo(2,"jack") - 错误处理
- go函数中可以有多个返回值,需要用多个变量接受,可以专门返回err eg
- 字符串函数//可以直接网上文档,这里不赘述
- 格式化输出(不用区分%s,%d,可以全部用%v)
fmt.printf("stu=%v",stu)//打印值s={1,Tom} fmt.printf("stu=%+v",stu)//打印值s={id:1 name:Tom} fmt.printf("stu=%#v",stu)//打印键-值s=main.student{id:1, name:"Tom"} //确定包的位置 - JSON转化
- json.Marshal(类型)//序列化
- json.Unmarshal(类型,&变量名)//反序列化 -注意
序列化后字段名首字母默认大写
特别是序列化结构体时,结构体成员变量需要时首字母大写才能序列号
如果需要字段名小写,可以在结构体成员变量后用``进行标注
eg:
type student struct {
id int //首字母未大写,序列化未空
name string
}
type student struct {
Id int //字母大写,序列化成功
Name string `json:name` //序列化后字段为name
}
- 时间管理
- 使用前导入time 包
- time.now() //获取当前时间
- time.Date(年,月,日,时,分,秒,0,时区)
- 声明变量 t:=time.Date(.....)后 可以用 t.year()等获取相关值
- time.Unix() 时间戳
- 字符串转数字
- strconv 包
- strconv.PareseInt(str,机制,64【返回64位精度】)
- strconv.Atoi(str) //eg: "1111"->1111
- 进程管理
- os.args 获取命令行参数
- os.Getenv("环境变量名")//获取环境变量
- os.setenv('环境变量名',值)//设定环境变量
- os.exec(str)执行命令行文件
项目实战
实战项目一--猜词游戏
本项目中我主要学习到的是go的用户输入的实现方法,总结如下
- 输入
- 流读取
reader := bufio.NewReader(os.Stdin) //从标准输入流中获取buf input, err := reader.ReadString('\n')//从输入流中以'/n'作为结束读取字符串 if err != nil { fmt.Println("error when input") continue } input = strings.TrimSuffix(input, "\r\n")//删除字符串末尾的"\r\n" - scanf方法读取(类似C和c++)【作业中要求使用】
scanf("%s",&变量)//注意此处不可以用%v替代所有类型- ps rand 函数的使用类似C和JAVA,一般都用时间戳作为seed
- 流读取
实战项目二---在线词典
本项目主要是介绍了工具网站和代码生成网站在实际项目中的使用,和json数据的处理
- 工具网站
- 代码生成 curlconverter.com
- json的格式化处理 oktools.iokde.com/
- ps:注意:
- 代码生成时注意
- windows中的curl命令生成go代码时,payload中 "key":"value"/key:"value",可能被解析为key:value,不确定是否是我的浏览器问题,但是还是写出来警醒以下。
- json的格式化处理
- 该网站只能实现一重json转格式化,可能出现转化不完全的情况,可以手动将未完全转化的部分单独转化一次 例如:火山翻译中details.details是一个结构体序列化但是嵌套后直接转化为string
- 代码生成时注意
- json 数据处理
- json.marshal(结构体)
- 返回二进制数组,和错误信息,若要打印字符串需用string转化
- json.unmarshal(需要进行序列化的二进制流,&存储用变量)
- 只返回error信息
- 反序列化结果即为存储用变量的结构体类型变量
- json.marshal(结构体)
- http请求
- http.client{设置参数,可为空}//用于构造一个客户端
- 使用时将地址赋给变量 eg
client=&http.client{}
- 使用时将地址赋给变量 eg
- http.NewRequest("请求方式",url,data)
- 注意:data是二进制形式,在构造时需用 bytes.NewReader生成
- 返回一个request请求变量和error信息
- client.do(req) 发送请求
- 返回相应信息与error信息
- http.client{设置参数,可为空}//用于构造一个客户端
实战项目3--socks5代理
本项目主要知识点时net包的使用和简单多线程的实现
- net包的使用
- net.listen(“协议类型/tcp/udp...”,地址:端口)
- 返回一个server类型+error
- server.accept()//返回一个连接对象(connection)//也是一个二进制流,存储用户发来的信息
- 利用bufio.NewReader(conn)获取发来的流
- 利用 coon.Write(byte[]) 向目标发送信息
- 其中网络协议协议相关内容此处不做叙述
- net.listen(“协议类型/tcp/udp...”,地址:端口)
- 简单的并发
- goroutine 主协程下可以有多个线程,并行的基础
go func1() go func2() return;- func1(),与func2()会与主携程并行运行,由于是并行操作所以很可能在func1,func2未运行完时,主协程结束,使func1,2也结束
- 解决方案
- 利用 sync.WaitGroup包,一个进程时启动一个 wg.add(1),一个进程完成后wg.Down() wg总数-1,同时主进程中加入wg.wait()即可等待所有进程执行完毕后再继续
- 利用 context库
ctx,err:=context.WithCancel(context.Background()) defr cancel() go func(){ func1() cancel() }()//调用该函数 go func(){ func2() cancel() } <-ctx.Down() 实现func1,func2任意一个完成即继续执行
以上就是本次课程一个简单总结
标题:走进 Go 语言基础语言 - 掘金