这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
关于golang的语法基础部分,具体可见我之前的记录性博客blog.csdn.net/m0_62976227…
接下来是本次课程的收获,可以说受益匪浅。 1. 小例子,构建简单的服务器,短短十行构建了可以传输静态文件的高并发高性能服务器
`package main
import (
"net/http"
)
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
http.ListenAndServe(":8080", nil)
} `
2.
3. 基础语法
Switch后可不写条件变量,在case里写,这就相当于多个ifelse嵌套
字符串操作
输出格式化
Go的JSON
要JSON的结构体内的结构变量名首字母必须大写,然后就可以用json.Marshal函数把结构体化成JSON文件。还可以用json.Unmarshal反序列化。其中MaeshalIndent指的是特定格式化JSON文件。
`package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int64 json:"age" //说明在json文件中此项小写
Hobby []string
}
func main() {
a := userInfo{Name: "John", Age: 16, Hobby: []string{"BallGame", "Reading"}}
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(buf)
fmt.Println(string(buf))
/*
[123 34 78 97 109 101 34 58 34 74 111 104 110 34 44 34 97 103 101 34 58 49 54 44 34 72 111 98 98 121 34 58 91 34 66 97 108 108 71 97 109 101 34 44 34 82 101 97 100 105 110 103 34 93 125]
{"Name":"John","age":16,"Hobby":["BallGame","Reading"]}
*/
buf, err = json.MarshalIndent(a, "", "\t")
//参数:每个键值对前面的东西。如\t就指的是下面“Name”前空个tab
if err != nil {
panic(err)
}
fmt.Println(string(buf))
/*
{
"Name": "John",
"age": 16,
"Hobby": [
"BallGame",
"Reading"
]
}
*/
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b)
//main.userInfo{Name:"John", Age:16, Hobby:[]string{"BallGame", "Reading"}}
}
`
Go的时间处理
这是一个固定不能变的时间2333
Go的字符串数字解析
三个参数: 字符串 进制
Go的进程分析
4. 实例:猜数游戏
`package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secret := rand.Intn(maxNum)
reader := bufio.NewReader(os.Stdin)
for {
fmt.Println("Please enter your guess number: ")
input, err := reader.ReadString('\n') //读取一行输入
if err != nil {
fmt.Println("An error occurred while reading")
return
}
input = strings.TrimSuffix(input, "\r\n") //去掉换行符,windows环境需要/r/n
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input.")
return
}
fmt.Println("Your guess is", guess)
if guess == secret {
fmt.Println("Correct! The num is", secret)
break
} else if guess > secret {
fmt.Println("Wrong! Your guess is bigger")
} else if guess < secret {
fmt.Println("Wrong! Your guess is smaller")
}
}
}
`
5. 实例:命令行字典
首先fanyi.caiyunapp.com/#/抓包得到请求的命令… as cURL(bash)),
把命令行代码转化为go代码。
但是注意到request body是固定的,我们不能固定,是想从变量中获取。因而接下来我们要学会如何自定义生成request body。
之前要构造JSON的存储结构,只需要构造变量一一对应的结构体。
解决了请求的发送,我们接下来要学会解析这个巨大的response,即反序列化:
依旧是使用上述的建一个结构体的方法,但我们不可能手写代码,因此我们需要用到代码生成网站oktools.net/json2go
点击copy value
再点击转换-嵌套
即可生成go的代码。再把这个结构体弄进去,后面多加一段打印出这个response的代码
然后进行重构,把上面的过程变成函数,取消硬编码,就可以华丽丽得到一个查字典的程序啦。
`package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
type DictResponse struct {
Rc int json:"rc"
Wiki struct {
KnownInLaguages int json:"known_in_laguages"
Description struct {
Source string json:"source"
Target interface{} json:"target"
} json:"description"
ID string json:"id"
Item struct {
Source string json:"source"
Target string json:"target"
} json:"item"
ImageURL string json:"image_url"
IsSubject string json:"is_subject"
Sitelink string json:"sitelink"
} 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"
}
type DictRequest struct {
TransType string json:"trans_type"
Source string json:"source"
UserID string json:"user_id"
}
func query(word string) {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
//用strings.NewReader把字符串转化成一个流
var data = bytes.NewReader(buf)
//参数:http的post请求、URL、data。其中data是一个流
req, err := http.NewRequest("POST", "api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
//设置一大堆请求的流
req.Header.Set("Connection", "keep-alive")
req.Header.Set("sec-ch-ua", " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97")
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36")
req.Header.Set("app-name", "xy")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Accept", "application/json, text/plain, /")
req.Header.Set("os-type", "web")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("sec-ch-ua-platform", "Windows")
req.Header.Set("Origin", "fanyi.caiyunapp.com")
req.Header.Set("Sec-Fetch-Site", "cross-site")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("Referer", "fanyi.caiyunapp.com/")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
//真正发起一个请求
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
//添加defer手动关闭流,防止内存泄漏
defer resp.Body.Close()
//把整个流读入成byte数组
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
//虽然得到了response,但可能是404、403这种,需要排除这种情况。
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode: ", resp.StatusCode, "body", string(bodyText))
}
var dictResponse DictResponse
//&是为了能写入结构体
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
for _, i := range dictResponse.Dictionary.Explanations {
fmt.Println(i)
}
}
func main() {
//如果输入的单词数小于2(最终运行是go run XXX.go + 单词)
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage:simpleDict WORD
example:simpleDict hello
`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
`
所以总结一下我们这个用第三方网站做出来的小玩具。实质上就是通过抓包和代码生成网站,得到request,发出request,从request中得到response,然后打印出response的过程,其中重点学习了JSON文件在go中的转换用法,以及请求发送与接受解析的API。
6. TCP echo server
`package main
import (
"bufio"
"log"
"net"
)
func main() {
// 增加一个端口,返回server
server, err := net.Listen("tcp", "127.0.0.1:1080")
if err != nil {
panic(err)
}
//死循环
for {
//接受请求
client, err := server.Accept()
if err != nil {
log.Printf("Accept failed %v", err)
continue
}
//成功的话返回链接,启动process子线程
go process(client)
}
}
func process(conn net.Conn) {
defer conn.Close()
//带缓冲的流,不是一个一个字节地读
reader := bufio.NewReader(conn)
for {
b, err := reader.ReadByte()
if err != nil {
break
}
_, err = conn.Write([]byte{b})
if err != nil {
break
}
}
}`