go语言基本+实战 | 青训营

122 阅读1分钟

基本语法

变量

  1. 可以手动确定类型,也可自动识别

    var i = 1
    int j = 1
    

    或者通过利用冒号语法

    f := float32(0)
    
  2. 不可变常量,没有类型,自动转化

    const s string = "constant"
    

分支

if 语句

相对于 c 语法,if 后面没有括号,但必须跟上分号

Switch 语句

不需要在每个case 后面跟上break;可以在 switch 后面不加任何的变量,然后在 case 里面写条件分支。这样代码相比用多个 if else 代码逻辑会更为清晰

switch {
    case t.Hour() < 12 :
        fmt.Println("It's before noon.")
    default:
        fmt.Println("It's afternoon.")
}

循环

只能使用for循环,也没有分号;可以配合 range 使用

基本元素集合

数组

声明数组

a := [5]int{1,2,3,4,5}

数组的访问就是经典方式

slice

通过 make数组获得,通过第二个参数指定长度

s := make([]string, 3)

可以使用append方法追加元素,需要重新赋值

s = append(s, "d")

使用copy方法拷贝

Map

声明时指定两种类型,中括号内为key,外面为value

m := make(map[string]int)

访问 Map 元素时,若key对应的值不存在,则会返回 0 和 false (两个值)

删除元素通过delete方法,删除 key 对应的键值对元素,此处删除的是名为m["one"]

delete(m, "one")

range

可以用来快速遍历数组,slice,map等

for 循环中使用时,返回两个值,第一个值为index,第二个值为value;对于map,第一个为key

nums := []int{1,2,3}
for i, num := range nums {
    fmt.Pringln(i, num)
}

函数

通过 func关键字指出;参数类型后置;返回类型在最后

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

并且可以返回多个值(一般为两个),常常使用第二个参数表示是否错误

指针

一般在函数中使用,用于传递参数;在函数内部直接修改原对象的值(不是拷贝值);

func add2ptr(n *int, a int) {
    *n += a
}
n := 2
add2ptr(&n, 1)

结构体

type user struct {
    name string
    password string
}

结构体赋值:

a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}

结构体方法

可以使用指针,修改结构体内的值

func (u user) checkPassword(password string) bool {
    return u.password == password
}
func (u *user) resetPassword(password string) {
    u.password = password
}

错误处理

在函数中使用单独的error返回值表示,然后通过简单的if-else语句处理

if err != nil{
    fmt.Pringln(err)
    return 
}

常用方法

JSON 处理

对于一个已有的结构体,保证其字段的首字母为大写,只需使用JSON.marshaler 去序列化,就能变成一个JSON字符串;可以在结构体字段的后面使用JSON tag ,修改JSON字符串的字段名

type userInfo struct {
    Name string
    Age int `json:"age"
    Hobby []string
}
//...

a := userInfo{Name: "wang", Age: 18, Hobby: []string{"golang", "TypeScript"}}
buf, err := json.Marshall(a)
if err != nil{
    panic(err)
}
fmt.Println(buf)

数字解析

字符串转换成整型或浮点型数字,使用strconv

f, _ := strconv.ParseFloat("1.234", 64)
n, _ := strconv.ParseInt("111", 10, 64)//十进制,精度为64

或者使用自动转化strconv.Atoi()

实战

猜谜游戏

  1. 生成随机数rand

    max := 100
    rand.Seed(time.Now().UnixNano())
    secretNumber := rand.Intn(maxNum)
    

    利用系统时间作为种子

  2. 获取用户输入 os.Stdin通过 bufio或者fmt.scanf获取

    reader := bufio.NewReader(os.Stdin)
    input, err := reader.ReadString('\n')
    input = strings.TrimSuffix(input, "\n") // 去除字符串后缀
    guess, err := strconv.Atoi(input)       // 字符串转换
    
  3. 然后实现判断逻辑和循环即可

在线词典

要点:发送http请求,解析JSON数据

发送http请求

生成请求可以通过Convert curl commands to code

  1. 创建客户端client := &http.Client

  2. 创建流数据data := string.NewReader("")

  3. 创建请求,设置请求头

    req, err := http.NewRequest("POST", {url}, data)
    req.Header.Set()// 通过工具生成
    
  4. 发送请求resp, err := client.Do(req)

  5. 关闭请求体defer resq.Body.Close()

  6. 读取返回结果,利用ioutil.ReadAll

    bodyText, err := ioutil.ReadALL(resp.Body)
    

    使用ioutil.ReadAll可以快速将数据从io.reader读取出来。但是当遇到大文件时,这个函数就会暴露出两个明显的缺点:

    1. 性能问题,文件越大,性能越差。
    2. 文件过大的话,可能直接撑爆内存,导致程序崩溃。

解析 JSON

  1. 创建对应的结构体, 使用JSON转Golang Struct - 在线工具 - OKTools

  2. 将返回结果去序列化

    var dicResponse DictResponse    //  DictResponse为创建的结构体
    err = json.Unmarshal(bodyText, &dictResponse)
    
  3. 然后可以通过dictResponse.字段的方式获取对应字段数据

SOCKS5代理

提供一个代理服务, 先与源主机建立连接, 然后与目标主机建立连接, 此后作为中介在两者间传递信息, 实现协议内容关键在于对报文的处理

  1. 开启监听端口, 并获取请求信息

    server, err := net.Listen("tcp", "127.0.0.1:1080")
    for {
       client, err := server.Accept()
    }