Go 语言基础代码分析与笔记
一、猜数游戏分析
1.1 功能概述
猜数游戏的目标是通过命令行输入,玩家需要猜一个随机生成的数字,程序会根据玩家的猜测给出提示,直到玩家猜对为止。
1.2 代码结构
代码的整体结构比较简单,主要包含以下部分:
- 随机数的生成
- 用户输入的获取
- 用户输入的验证和提示
- 程序的循环执行直到猜对为止
1.3 代码解析
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
包导入部分
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)
随机数的生成
maxNum := 100: 定义了一个常量maxNum,用于表示猜测数字的上限(0 到 99之间的整数)。rand.Seed(time.Now().UnixNano()): 使用当前的时间戳作为种子初始化随机数生成器,确保每次运行程序生成的随机数不同。secretNumber := rand.Intn(maxNum): 生成一个 0 到maxNum-1(即 0 到 99)之间的随机整数,作为用户要猜的秘密数字。
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
提示用户输入
fmt.Println("Please input your guess"): 输出提示信息,告知用户输入他们的猜测。reader := bufio.NewReader(os.Stdin): 创建一个新的bufio.Reader,用于从标准输入读取数据。
for {
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
continue
}
input = strings.Trim(input, "\r\n")
用户输入循环
for {}: 一个无限循环,程序会一直运行直到用户猜对数字为止。input, err := reader.ReadString('\n'): 从标准输入读取用户输入的数据,直到遇到换行符\n。如果读取错误,打印错误信息并继续下一次循环。input = strings.Trim(input, "\r\n"): 去除用户输入中的换行符和回车符,确保输入的纯净。
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
continue
}
输入验证
guess, err := strconv.Atoi(input): 将用户输入的字符串转换为整数。如果转换失败(即输入的不是有效的整数),则进入err分支,提示用户重新输入。
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
}
}
}
猜测判断与提示
-
fmt.Println("You guess is", guess): 打印用户输入的猜测。 -
判断猜测是否正确:
- 如果猜测大于秘密数字,提示猜测数字大了。
- 如果猜测小于秘密数字,提示猜测数字小了。
- 如果猜测正确,打印成功信息并跳出循环
break。
总结
该游戏是通过一个循环不断接受用户的输入,并根据猜测给出反馈,直到用户猜对数字。程序中使用了bufio进行输入处理,使用strconv进行类型转换,且每次用户输入后,都会根据输入与随机数进行对比,并给出相应的提示。
二、命令行词典代码分析
2.1 功能概述
该部分代码实现了一个查询词典的功能,用户通过命令行传入一个英文单词,程序会通过 API 请求查询该单词的相关信息,并展示其发音、解释和词义等内容。
2.2 代码结构
代码的主要结构包括:
- 定义请求和响应的结构体
- 通过 HTTP 请求调用外部 API
- 解析 API 返回的数据
- 格式化输出查询结果
2.3 代码解析
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
包导入部分
bytes: 提供了处理字节切片的函数,常用于处理请求和响应的内容。encoding/json: 用于解析和生成 JSON 数据。fmt: 格式化输出和打印信息。ioutil: 提供了文件和 I/O 操作的工具函数,这里用于读取 HTTP 响应的主体。log: 用于日志记录和错误处理。net/http: 提供了 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"`
}
请求与响应结构体
DictRequest:用于构建请求的结构体,包含了翻译类型、源单词和用户ID(虽然在此示例中未使用user_id)。DictResponse:用于接收 API 响应的结构体,结构体内包含了从 API 返回的各个字段,如发音、词义、同义词、反义词等。
func query(word string) {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
请求构建与发送
client := &http.Client{}: 创建一个 HTTP 客户端对象,用于发送请求。request := DictRequest{TransType: "en2zh", Source: word}: 构建请求体,设置翻译类型为从英文到中文,源单词为用户传入的单词。- `buf, err := json.Marshal(request)
`: 将请求体序列化为 JSON 格式的字节流。
req, err := http.NewRequest("POST", ...): 构造 HTTP POST 请求,指定请求的 URL 和请求体。
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))
}
响应处理
resp, err := client.Do(req): 发送请求并获取响应。defer resp.Body.Close(): 确保响应体在函数执行完后被关闭,释放资源。bodyText, err := ioutil.ReadAll(resp.Body): 读取响应的主体内容。if resp.StatusCode != 200: 检查响应的状态码,如果不是 200(表示成功),则输出错误信息。
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)
}
解析 JSON 响应并输出
var dictResponse DictResponse: 声明一个DictResponse变量,用于存储解析后的响应数据。err = json.Unmarshal(bodyText, &dictResponse): 将响应的 JSON 数据反序列化到dictResponse变量中。- 打印单词的发音、同义词、解释等内容。
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
主函数
- 检查命令行参数是否正确,若用户未提供单词,则输出用法信息并退出。
- 获取命令行参数中的单词并调用
query函数查询其相关信息。
总结
这篇笔记对两个 Go 语言示例进行了详细分析,第一个是一个经典的猜数游戏,使用了 Go 的基本输入输出功能、随机数生成和条件判断。第二个示例是一个通过 API 查询词典的程序,涉及了 HTTP 请求的构建与发送、JSON 的解析与处理。