Go语言入门实战: 猜谜游戏+在线词典

包含基础语法和入门Go语言的3个案例

速览基础语法

对于耳熟能详的顺序结构、分支结构(if else-if else、switch)、循环结构(for)不作赘述。

数组: 长度固定的元素序列

package main

import "fmt"

func main() {
    var a [5]int              // 声明数组
    a[4] = 100                // 赋值
    fmt.Println(a[4], len(a)) // 打印元素和长度

    b := [5]int{1, 2, 3, 4, 5} // 赋值
    fmt.Println(b)

    var twoD [2][3]int
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}

运行结果

00 5
[1 2 3 4 5]
2d:  [[0 1 2] [1 2 3]]

切片: 如同长度可变的数组,用make创建

package main

import "fmt"

func main() {
    s := make([]string, 3)
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("get 2: ", s[2])
    fmt.Println("len: ", len(s))

    // 加入元素 返回切片
    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println(s)

    c := make([]string, len(s))
    copy(c, s)
    fmt.Println(c)

    // 切片
    fmt.Println(s[2:5])
    fmt.Println(s[:5])
    fmt.Println(s[2:])

    good := []string{"g", "o", "o", "d"}
    fmt.Println(good)
}

运行结果

get 2:  c
len:  3
[a b c d e f]
[a b c d e f]
[c d e]
[a b c d e]
[c d e f]
[g o o d]

map: 如同字典,使用make创建

package main

import "fmt"

func main() {
    m := make(map[string]int) // 创建map
    m["one"] = 1
    m["two"] = 2
    fmt.Println(m)
    fmt.Println(len(m))
    fmt.Println(m["one"])
    fmt.Println(m["unknown"]) // 不存在的键
    r, ok := m["unknown"]
    fmt.Println(r, ok)
    delete(m, "one")                         // 删除键值
    m2 := map[string]int{"one": 1, "two": 2} // 赋值
    var m3 = map[string]int{"one": 1, "two": 2}
    fmt.Println(m2, m3)
}

执行结果

map[one:1 two:2]
2
1
0
0 false
map[one:1 two:2] map[one:1 two:2]

range函数

package main

import "fmt"

func main() {
    nums := []int{2, 3, 4}
    sum := 0
    // 遍历切片
    for i, num := range nums {
        sum += num // 求和
        if num == 2 {
            fmt.Println("index:", i, "num", num)
        }
    }
    fmt.Println(sum)

    m := map[string]string{"a": "A", "b": "B"}
    // 遍历map
    for k, v := range m {
        fmt.Println(k, v)
    }
    for k := range m {
        fmt.Println("key", k)
    }
}

运行结果

index: 0 num 2
9
a A
b B
key a
key b

字符串操作,使用strings

package main

import (
    "fmt"
    "strings"
)

func main() {
    a := "hello"
    fmt.Println(strings.Contains(a, "ll"))                // 是否包含
    fmt.Println(strings.Count(a, "l"))                    // 统计个数
    fmt.Println(strings.HasPrefix(a, "he"))               // 开头字符串
    fmt.Println(strings.Index(a, "ll"))                   // 返回下标
    fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // 连接字符串
    fmt.Println(strings.Repeat(a, 2))                     // 重复
    fmt.Println(strings.Replace(a, "e", "E", -1))         // 替换
    fmt.Println(strings.Split("a-b-c", "-"))              // 切割
    fmt.Println(strings.ToLower(a))                       // 大小写转换
    fmt.Println(strings.ToUpper(a))
    fmt.Println(len(a)) // 求长度
    b := "你好"
    fmt.Println(len(b))
}

运行结果

true
2
true
2
he-llo
hellohello
hEllo
[a b c]
hello

JSON数据处理

package main

import (
    "encoding/json"
    "fmt"
)

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

func main() {
    a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
    buf, err := json.Marshal(a)
    if err != nil {
        panic(err)
    }
    fmt.Println(buf)                           // 打印出来的是16进制数字
    fmt.Println(string(buf))                   // 转成JSON字符串
    buf, err = json.MarshalIndent(a, "", "\t") 
    if err != nil {
        panic(err)
    }
    fmt.Println(string(buf))

    var b userInfo
    // JSON反序列化
    err = json.Unmarshal(buf, &b) // 反序列化 存入结构体
    if err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", b)
}

打印结果

[123 34 78 97 109 101 34 58 34 119 97 110 103 34 44 34 97 103 101 34 58 49 56 44 34 72 111 98 98 121 34 58 91 34 71 111 108 97 110 103 34 44 34 84 121 112 101 83 99 114 105 112 116 34 93 125]
{"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
{
        "Name": "wang",
        "age": 18,
        "Hobby": [
                "Golang",
                "TypeScript"
        ]
}
main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}

数字解析,使用strconv,对数字字符串进行转化

package main

import (
    "fmt"
    "strconv"
)

func main() {
    f, _ := strconv.ParseFloat("1.234", 64)
    fmt.Println(f)
    n, _ := strconv.ParseInt("111", 10, 64)
    fmt.Println(n)
    n, _ = strconv.ParseInt("0x1000", 0, 64)
    fmt.Println(n)
    n2, _ := strconv.Atoi("123") 
    fmt.Println(n2)
    n2, err := strconv.Atoi("AAA") // 数据类型出错 应传入数字
    fmt.Println(n2, err)
}

运行结果

1.234
111
4096
123
0 strconv.Atoi: parsing "AAA": invalid syntax

获取进程信息,使用os

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    fmt.Println(os.Args)  // 获取命令行参数
    fmt.Println(os.Getenv("PATH")) // 获取路径
    fmt.Println(os.Setenv("AA", "BB")) // 设置环境变量

    // 执行终端指令
    buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(buf))
}

猜谜游戏

这是一个很简单的流程: 输入一个数字,程序会回复和答案相比是大还是小,直到猜对这个数字。

首先解决生成随机数的问题,Go语言中使用rand库中的函数来生成随机数,这依赖两个函数: rand.Seed设置随机数种子,rand.Intn生成随机数。

如下述文档所示:

$ go doc rand.Sed
package rand // import "math/rand"

func Seed(seed int64)
$ go doc rand.Intn
package rand // import "math/rand"

func Intn(n int) int

首先试图生成一个随机数

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    maxNum := 100 // 规定最大值
    rand.Seed(time.Now().UnixNano()) // 以时间戳来设置随机数种子
    secretNumber := rand.Intn(maxNum)
    fmt.Println("The secret number is", secretNumber)
}

这样生成的随机数在0到100之间

如下代码增加了与用户的交互,读取用户输入

    // 与用户交互
    fmt.Println("Please input your guess: ")
    reader := bufio.NewReader(os.Stdin)
    input, err := reader.ReadString('\n') // 读入字符串 以换行为结尾
    if err != nil {
        fmt.Println("An error occured while reading input. Please try again", err)
        return
    }
    input = strings.TrimSuffix(input, "\n") // 去除换行符

    guess, err := strconv.Atoi(input) // 转化为数字
    if err != nil {
        fmt.Println("Invalid input. Please enter an integer value")
        return
    }
    fmt.Println("You guess is", guess)

下面实现对用户输入的判断

	// 判断逻辑
	if guess > secretNumber {
		fmt.Println("Your guess is bigger than the secret number. Please try again")
	} else if guess < secretNumber {
		fmt.Println("Your guess is smaller than the secret number. Please try again")
	} else {
		fmt.Println("Correct, you legend!")
	}

将这个判断放入循环中,使玩家能够猜测多次,同时将原先的return改为coutinue

完整代码

package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
)

func main() {
	maxNum := 100
	rand.Seed(time.Now().UnixNano())
	secretNumber := rand.Intn(maxNum)
	//fmt.Println("The secret number is", secretNumber)

	// 与用户交互
	for {
		fmt.Print("Please input your guess: ")
		reader := bufio.NewReader(os.Stdin)
		input, err := reader.ReadString('\n') // 读入字符串 以换行为结尾
		if err != nil {
			fmt.Println("An error occured while reading input. Please try again", err)
			continue
		}
		input = strings.TrimSuffix(input, "\n") // 去除换行符

		guess, err := strconv.Atoi(input) // 转化为数字
		if err != nil {
			fmt.Println("Invalid input. Please enter an integer value")
			continue
		}
		fmt.Println("You guess is", guess)

		// 判断逻辑
		if guess > secretNumber {
			fmt.Println("Your guess is bigger than the secret number. Please try again")
		} else if guess < secretNumber {
			fmt.Println("Your guess is smaller than the secret number. Please try again")
		} else {
			fmt.Println("Correct, you legend!")
			break
		}
	}
}

运行

Please input your guess: 10
You guess is 10
Your guess is smaller than the secret number. Please try again
Please input your guess: 90
You guess is 90
Your guess is bigger than the secret number. Please try again
Please input your guess: 50
You guess is 50
Your guess is smaller than the secret number. Please try again
Please input your guess: 70
You guess is 70
Your guess is bigger than the secret number. Please try again
Please input your guess: 60
You guess is 60
Your guess is smaller than the secret number. Please try again
Please input your guess: 75
You guess is 75
Your guess is bigger than the secret number. Please try again
Please input your guess: 65
You guess is 65
Correct, you legend!

在线词典

命令行运行,根据输入的英文单词来输出其中文含义和音标

这要借助于一个翻译网站: https://fanyi.caiyunapp.com/

输入一个单词 good,点击翻译

通过使用浏览器的抓包工具可以发现翻译其实是在对如下URL发起POST请求

请求中的payload如下

{
    "trans_type": "en2zh",
    "source": "good"
}

source就是输入的单词,trans_type是翻译方式,en2zh就表示英译汉

那么下面只要构造这个HTTP请求即可,但由于其参数众多,手打比较麻烦,可以利用在线工具自动生成一些代码。

在线网站: Convert curl commands to code

右击刚刚的URL,选择到Copy as cURL

然后将这段信息复制到在线工具中,如下就会生成对应的代码

如下:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func main() {
	client := &http.Client{}
	var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
	req, err := http.NewRequest("POST", "https://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", "Chromium";v="99", "Google Chrome";v="99"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 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", `"Linux"`)
	req.Header.Set("Origin", "https://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", "https://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 resp.Body.Close()
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", bodyText)
}

运行这段代码,输出如下,这是一长串的JSON

{"rc":0,"wiki":{"known_in_laguages":63,"description":{"source":"tangible and intangible thing, except labor tied services, that satisfies human wants and provides utility","target":null},"id":"Q28877","item":{"source":"good","target":"\u5546\u54c1"},"image_url":"http:\/\/www.caiyunapp.com\/imgs\/link_default_img.png","is_subject":"true","sitelink":"https:\/\/www.caiyunapp.com\/read_mode\/?id=625b4b949c0120504d1e7b69"},"dictionary":{"prons":{"en-us":"[g\u028ad]","en":"[gud]"},"explanations":["a.\u597d\u7684;\u5584\u826f\u7684;\u5feb\u4e50\u7684;\u771f\u6b63\u7684;\u5bbd\u5927\u7684;\u6709\u76ca\u7684;\u8001\u7ec3\u7684;\u5e78\u798f\u7684;\u5fe0\u5b9e\u7684;\u4f18\u79c0\u7684;\u5b8c\u6574\u7684;\u5f7b\u5e95\u7684;\u4e30\u5bcc\u7684","n.\u5229\u76ca;\u597d\u5904;\u5584\u826f;\u597d\u4eba","ad.=well"],"synonym":["excellent","fine","nice","splendid","proper"],"antonym":["bad","wrong","evil","harmful","poor"],"wqx_example":[["to the good","\u6709\u5229,\u6709\u597d\u5904"],["good, bad and indifferent","\u597d\u7684,\u574f\u7684\u548c\u4e00\u822c\u7684"],["good innings","\u957f\u5bff"],["good and ...","\u5f88,\u9887;\u5b8c\u5168,\u5f7b\u5e95"],["do somebody's heart good","\u5bf9\u67d0\u4eba\u7684\u5fc3\u810f\u6709\u76ca,\u4f7f\u67d0\u4eba\u611f\u5230\u6109\u5feb"],["do somebody good","\u5bf9\u67d0\u4eba\u6709\u76ca"],["be good for","\u5bf9\u2026\u6709\u6548,\u9002\u5408,\u80dc\u4efb"],["be good at","\u5728\u2026\u65b9\u9762(\u5b66\u5f97,\u505a\u5f97)\u597d;\u5584\u4e8e"],["as good as one's word","\u4fe1\u5b88\u8bfa\u8a00,\u503c\u5f97\u4fe1\u8d56"],["as good as","\u5b9e\u9645\u4e0a,\u51e0\u4e4e\u7b49\u4e8e"],["all well and good","\u4e5f\u597d,\u8fd8\u597d,\u5f88\u4e0d\u9519"],["a good","\u76f8\u5f53,\u8db3\u8db3"],["He is good at figures . ","\u4ed6\u5584\u4e8e\u8ba1\u7b97\u3002"]],"entry":"good","type":"word","related":[],"source":"wenquxing"}}

查看这段自动生成的代码

data变量保存了payload数据,http.NewRequest构造一个HTTP请求,第一个参数传入了请求方式,第二个参数URL,第三个参数就是上述的payload

下面的req.Header.Set都是在设置请求头,最后调用了client.Do向目标发起了实际的请求

ioutil.ReadAll(resp.Body) 获取回复结果的Body

为了能将用户输入放入请求当中,下面要使用JSON序列化,构造JSON数据

于是定义如下结构体:

type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
	UserID    string `json:"user_id"`
}

利用如下代码进行JSON序列化,替换原来的data

因为json.Marshal返回的是byte型数据,因此要进行类型转化,然后再赋值给data

	client := &http.Client{}
	request := DictRequest{TransType: "en2zh", Source: "good"}
	buf, err := json.Marshal(request)
	if err != nil {
		log.Fatal(err)
	}
	var data = bytes.NewBuffer(buf)

运行得到的结果和之前应该是一样,但显然得到的结果是杂乱的JSON数据,因此要对其进行解析。

下面要解析response body,如果按照常规思路,自己手动定义一个结构体,再将这段JSON反序列化赋值给结构体变量无疑是极其复杂的,因此还是利用在线生成工具。

链接: JSON转Golang Struct - 在线工具 - OKTools

将刚刚得到的JSON数据放到输入框中再点击转换-嵌套

复制后放到代码中

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"`
}

那么原本的bodyText变量就不直接打印了,而是JSON反序列化后放入结构体中

	var dictResponse DictResponse
	err = json.Unmarshal(bodyText, &dictResponse)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%#v\n", dictResponse)

打印结果,同样是一长串的数据

main.DictResponse{Rc:0, 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\"" }{KnownInLaguages:63, Description:struct { Source string "json:\"source\""; Target interface {} "json:\"target\"" }{Source:"tangible and intangible thing, except labor tied services, that satisfies human wants and provides utility", Target:interface {}(nil)}, ID:"Q28877", Item:struct { Source string "json:\"source\""; Target string "json:\"target\"" }{Source:"good", Target:"商品"}, ImageURL:"http://www.caiyunapp.com/imgs/link_default_img.png", IsSubject:"true", Sitelink:"https://www.caiyunapp.com/read_mode/?id=625b4b949c0120504d1e7b69"}, Dictionary:stct { 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\"" }{Prons:struct { EnUs string "json:\"en-us\""; En string "json:\"en\"" }{EnUs:"[gʊd]", En:"[gud]"}, Explanations:[]string{"a.好的;善良的;快乐的;真正的;宽大的;有益的;老练的;幸福的;忠实的;优秀的;完整的;彻底"}, Synonym:[]string{"excellent", "fine", "nice", "splendid", "proper"}, Antonym:[]string{"bad", "wrong", "evil", "harmful", "poor"}, WqxExample:[][]string{[]string{"to the good", "有利,有好处"}, []st"good, bad and indifferent", "好的,坏的和一般的"}, []string{"good innings", "长寿"}, []string{"good and ...", "很,颇;完全,彻底"}, []string{"do somebody's heart good", "对某人的心脏有益,使某人感到愉快" "对某人有益"}, []string{"be good for", "对…有效,适合,胜任"}, []string{"be good at", "在…方面(学得,做得)好;善于"}, []string{"as good as one's word", "信守诺言,值得信赖"}, []string{"as good as", "实际上good", "也好,还好,很不错"}, []string{"a good", "相当,足足"}, []string{"He is good at figures . ", "他善于计算。"}}, Entry:"good", Type:"word", Related:[]interface {}{}, Source:"wenquxing"}}

下一步是从结构体中取出翻译的结果

观察原来的JSON数据就可知中文释义在dictionary的explanations下,音标在prons下

	fmt.Println("UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
	for _, item := range dictResponse.Dictionary.Explanations {
		fmt.Println(item)
	}

这段代码可以打印出想要的数据,因为Explanations是一个字符串类型的切片,其中存放了多个字符串,所以使用for-range进行遍历打印

最后还要能接收用户的输入,将输入放入请求中

	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
		os.Exit(1)
	}
	word := os.Args[1]

如上代码是获取命令行输入,赋给word变量

将word放入结构体,作为Source字段:

request := DictRequest{TransType: "en2zh", Source: word}

加入对HTTP响应码的判断,算是提升程序健壮性

	if resp.StatusCode != 200 {
		log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
	}

最后的完整代码

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

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 {
		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"`
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
		os.Exit(1)
	}
	word := os.Args[1]
	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)
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 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", `"Linux"`)
	req.Header.Set("Origin", "https://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", "https://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 resp.Body.Close()
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	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 _, item := range dictResponse.Dictionary.Explanations {
		fmt.Println(item)
	}
}

编译和运行:

$ go build demo.go
$ ./demo hello
hello UK: [ˈheˈləu] US: [həˈlo]
int.喂;哈罗
n.引人注意的呼声
v.向人呼(喂)

SOCKS5代理

如下是一个大致的流程

SOCKS5_百度百科

在实现SOCKS5代理服务器之前先实现一个TCP回显服务器,熟悉一些网络编程的内容

package main

import (
	"bufio"
	"log"
	"net"
)

func main() {
	server, err := net.Listen("tcp", "127.0.0.1:10800") // 监听
	if err != nil {
		log.Fatal(err)
	}
	for {
		client, err := server.Accept()  // 接受连接并返回
		if err != nil {
			log.Printf("Accept failed: %v", err)
			continue
		}
		go process(client) // 启动一个goroutine来处理连接
	}
}

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
		}
	}
}

运行上述代码后,使用nc命令连接,输入什么服务器就返回什么

$ nc 127.0.0.1 10800
Hello 
Hello

(未完待续)

posted @ 2022-05-10 00:32  N3ptune  阅读(100)  评论(0编辑  收藏  举报