[ Go语言基础 | 青训营笔记]

114 阅读4分钟

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

Go语言基础

Go语言的特性与优势

  1. 高性能、高并发(原生支持go routine)
  2. 语法简单,易于学习(类似于C语言,但简化了很多特性)
  3. 标准库丰富(标准库自带http包,网络包等常用库)
  4. 工具链完善(编译、格式化、包管理、代码提示、测试框架等都是自带的)
  5. 采用静态链接(发布可执行文件时不用面对库的兼容性问题)
  6. 编译速度快(比C++快很多)
  7. 跨平台(Win/Linux/Mac,交叉编译)
  8. 支持垃圾回收

入门

开发环境配置

  • 安装Go语言

    pacman -S go
    
  • 配置集成开发环境

    • VS Code,需要配置插件
    • Jetbrains的Goland

基础语法

Hello World程序

package main
​
import "fmt"func main(){
    fmt.Println("Hello World")
}

一些说明:

  • package main: 包的名字
  • import "fmt" 导入fmt包
  • func main() 定义主函数
  • fmt.Println 一个包里面,大写字母开头的符号是导出的

变量

使用var关键字来定义变量

var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
  • 常见的变量类型分类:整数、浮点、字符串、布尔值
  • 变量的类型写在变量名后面,有初值的情况下可以自动推导类型
  • 可以使用 := 快速定义一个变量(不能用于全局变量)
  • 使用const代替var来定义常量

if控制流

if 7 % 2 == 0{
    fmt.Println("7 is even")
}else{
    fmt.Println("7 is odd")
}
  • 不使用括号

循环控制流

Go语言的循环只有for一个关键字,并且同if一样不使用括号

但是可以有多种形式

for{
    //statement
}// 死循环
for i:=1; i<0;i++{  //可以省略任意分句
    //statement
}
for x >=0 {
    //statment
}

break和continue的使用与C/C++类似

switch case控制流

与C/C++的区别:

  1. 不需要额外的break语句,如果想像C/C++一样,使用fallthrough
  2. 条件不需要是整数类型,可以是任意类型,即可以完全替代else if语句

数组与切片

定义数组:

var a [5]int

a的类型是[5]int,长度是类型的一部分

创建切片:

b := make([]int, 5)

需要注意append时,需要使用append的返回值

map

使用make创建一个map

m := make(map[string]int)

使用delete删除kv对

delete(m, "key")

返回值的获取:val, ok := m["key"]

遍历map:for k,v := range m {...}

函数

func add(a int, b int) (int, int){
    return a+b, a-b
}

同变量声明一样,返回值类型写在函数声明最后面

此外,Go语言原生支持多返回值(多见于if err!=nil的前面)

指针

可以认为Go中的指针是C/C++中指针的简化版

不支持指针的加减操作,即无法通过*(ptr+i)这样的形式遍历数组了

结构体

定义结构体

type user struct{
    name string
    age  int
}

定义成员函数

func (u *user) grow() int{
    u.age ++
    return u.age
}
​
_ = u.grow()

错误处理

通常使用多返回值配合err的形式,例如

v, err := findUser(u)
if err!= nil{
    // handle error
}

字符串处理

导入strings包,然后使用如strings.Contains(s, substr)这样的字符串处理函数。

另外,获取字符串长度可以使用内置函数len(s)

导入fmt包可以对字符串进行格式化处理,相比于C,新增了一个%v的类型描述符,可以自动匹配传入参数类型。

处理json

使用标准库的encoding/json

具体而言,使用json.Marshal(b)json.Unmarshal(buf, &b)两个函数来序列化/反序列化json对象

需要保证struct的成员是导出的,此外可以使用json: tag来自定义字段标签。

时间处理

使用time

使用time.Now()获取当前时间

使用2006-01-02 15:04:05来格式化时间字符串

数字与字符串的转换

使用strconv

使用strconv.ParseIntstrconv.ParseFloat来从字符串中解析数值数据,使用strconv.Atoi来将数值数据转换成对应的字符串。

进程参数,环境变量获取

使用os

使用os.Args来获取启动时的进程参数

使用os.Getenv("ENVNAME")来获取环境变量,类似的,使用os.Setenv("AA","BB")来设置环境变量

三个例子

猜数字游戏

使用到前面未介绍的库函数:

  • math/rand

    通过rand.Seed(time.Now().UnixNano())来初始化随机数种子

  • bufio

    创建读取流: reader := bufio.NewReader(os.Stdin)

命令行词典

如何获取API

  • 使用开发者工具,Copy As cURL
  • curlconverter.com/#go) 中粘贴并得到Go语言的http请求代码
  • 复制到项目中,进行修改

代码生成工具

Socks5代理

  • 使用cURL来测试:

    curl --socks5 127.0.0.1:1080 -v http://g.cn
    
  • 使用net包

    server, err := net.Listen("tcp", "127.0.0.1:1080")
    if(err!=nil){
        panic(err)
    }
    for{
        client, err:= server.Accept()
        ...
    }
    
  • Socks5协议

    Socks5 - RFC1928

  • 客户端 <--> Socks5服务器 <--> 目标服务器