基础语法、实战案例
1. 基础语法中值得注意的地方
- go是一门强类型语言:变量的使用要严格符合定义,先定义后使用。
- 没有while循环。
- 取地址符是&,声明指针是*,与C一致。
- 声明变量的时候要注意什么时候使用
:=。
var ( // 这种因式分解关键字的写法一般用于声明全局变量
a int
b bool
)
- 函数返回值可以有多个。
- 切片slice和Python类似,支持动态扩容,append追加元素。
s := make([], string, 3) - 异常处理的机制:以前学过一点C#,是用
try, catch实现异常处理的,感觉比较繁琐,有时候不知道将哪一部分包起来好。Go的异常处理感觉就简单清晰很多,感觉比较舒服。
入门小项目1:在线词典-抓包
基本操作如下:
- 在彩云翻译抓取cURL,丢到Converter里转化成go源码,成功运行后会输出JSON字符串
- 为了实现获取动态输入,要做JSON序列化:构造相应结构体即可,在此处可以做在线代码生成。
- 解析获取的response body同理,具体位置在:点击“翻译”,右键网页-检查-network-dict(注意是post类型的请求)-preview
代码块
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
)
// 实现获取动态输入,要做JSON序列化:构造相应结构体即可
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 {
} `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) {
// 可以指定一些重要参数,比如timeout
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewBuffer(buf)
// 以流传输,减少内存占用
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("authority", "api.interpreter.caiyunai.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "2a717e9a6a196072ed3294ce3d8c19f6")
req.Header.Set("origin", "https://fanyi.caiyunapp.com")
req.Header.Set("os-type", "web")
req.Header.Set("os-version", "")
req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
req.Header.Set("sec-fetch-dest", "empty")
req.Header.Set("sec-fetch-mode", "cors")
req.Header.Set("sec-fetch-site", "cross-site")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
// 真正发起的请求
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
// 关闭流,防止泄露
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
// 防御式编程
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
// 将得到的bodyText反序列化
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
// #v理解为全部打印, Printf打印带格式化的字符串,Println打印字符串和变量
// fmt.Printf("%#v\n", dictResponse)
// 只打印需要的信息
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.Printf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
入门项目2.Socks5代理
- SOCKS5代理看上去很复杂,实际上它只是IP代理协议中的一种,同时又是最重要、最流行的一种,真正的匿名代理只能由SOCKS5协议的代理IP来实现。
- 介绍了代理的运行原理。
- 一个服务项目:TCP echo server: 监听,并原路返回收到的信息的TCP server。使用nc命令要用到netcat工具,注意windows自带的杀软会被误报病毒,要添加白名单。
最后来试着用Go写一个LeetCode算法题
[题目链接](1246. 删除回文子数组 - 力扣(LeetCode)
解题方法
区间DP的套路个人感觉比较固定,通常状态都表示为:使区间满足条件的最小操作数,注意是闭区间。初始化为,其余为正无穷。状态转移时第一重循环枚举左端点,第二重循环枚举数组长度。
考虑状态转移的几种情况:
Case1:
若,则 否则,注意特判越界的情况
Case2
整个数组由几个回文子数组构成,如 此时要枚举一下中间的分割点,
Code
func minimumMoves(arr []int) int {
var n := len(arr)
var dp [101][101]int
for i := 0; i < len(arr); i++ {
dp[i][i] = 1
}
for i := 0; i < len(arr)-1; i++ {
if arr[i] == arr[i+1] {
dp[i][i+1] = 1
} else {
dp[i][i+1] = 2
}
}
for l := 2; l < len(arr); l++ {
for i := 0; i+l < len(arr); i++ {
j := i + l
dp[i][j] = l + 1
for k := 0; k <= l; k++ {
if dp[i][i+k]+dp[i+k+1][j] < dp[i][j] {
dp[i][j] = dp[i][i+k] + dp[i+k+1][j]
}
}
if arr[i] == arr[j] {
if dp[i+1][j-1] < dp[i][j] {
dp[i][j] = dp[i+1][j-1]
}
}
}
}
return dp[0][len(arr)-1]
}
总结
- Socks5的项目其实还没有实现,仅仅只是实现了一个CP echo server的监听服务。因为对Socks5这个概念的了解还比较模糊,待后续进一步学习再回头来看这个项目。
- “抓包”这个概念虽然已经在很多地方都听到过了,但实战起来还是第一次,有了比较初步的认识。
- 做这个小项目的同时,初步学习了GO语言的基础语法。以前只学过C++和Python这类面向对象思想的语言,所以第一次上手接触还是感到非常新奇的。