当前位置: 首页 > ops >正文

【Go】2、Go语言实战

前言

        本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。


前置知识

        本篇将涉及到一些在命令行的输入输出操作,之前我们已经学习了fmt包用于输出内容,下面将介绍bufio包用于读入数据。

bufio包简介

        bufio 是 Go 标准库中一个强大的带缓冲 I/O 包,它通过提供缓冲机制来优化 I/O 操作性能,特别适合处理大量小数据块的读写场景。

        bufio包主要由三个组件构成:

  • Reader - 带缓冲的读取器

  • Writer - 带缓冲的写入器

  • Scanner - 高级扫描器

      下面将分别对三个组件中的关键方法进行解读。

    Reader

            使用场景:

    • 需要精确控制读取过程时

    • 处理二进制数据或特定分隔符

    • 需要预读(Peek)功能时

    | 方法签名                                                                 | 描述                     | 返回值          | 应用场景                 |
    |-------------------------------------------------------------------------|--------------------------|-----------------|--------------------------|
    | `func (b *Reader) Read(p []byte) (n int, err error)`                    | 读取数据到字节切片       | 字节数, 错误    | 读取二进制数据           |
    | `func (b *Reader) ReadByte() (byte, error)`                             | 读取单个字节             | 字节值, 错误    | 处理二进制格式           |
    | `func (b *Reader) ReadRune() (r rune, size int, err error)`             | 读取单个 Unicode 字符    | 字符, 字节数, 错误 | 处理多字节编码文本       |
    | `func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)`   | 读取一行文本             | 行内容, 是否截断, 错误 | 处理文本文件             |
    | `func (b *Reader) ReadString(delim byte) (string, error)`               | 读取直到分隔符           | 字符串, 错误    | 按分隔符读取内容         |
    | `func (b *Reader) ReadBytes(delim byte) ([]byte, error)`                | 读取字节直到分隔符       | 字节切片, 错误  | 需要原始字节数据         |
    | `func (b *Reader) Peek(n int) ([]byte, error)`                          | 预读而不移动指针         | 字节切片, 错误  | 查看后续内容             |
    | `func (b *Reader) Buffered() int`                                       | 获取缓冲区的字节数       | 字节数          | 检查缓冲区状态           |
    | `func (b *Reader) Reset(r io.Reader)`                                   | 重置 Reader 关联的源     | 无              | 重用 Reader 对象         |

    Writer

            使用场景:

    • 频繁写入小量数据

    • 需要高性能文件写入

    • 格式化输出到控制台或文件

    | 方法签名                                                                 | 描述                     | 返回值          | 应用场景                 |
    |-------------------------------------------------------------------------|--------------------------|-----------------|--------------------------|
    | `func (b *Writer) Write(p []byte) (nn int, err error)`                  | 写入字节切片             | 写入字节数, 错误 | 写入二进制数据           |
    | `func (b *Writer) WriteByte(c byte) error`                              | 写入单个字节             | 错误            | 写入特定字节值           |
    | `func (b *Writer) WriteRune(r rune) (size int, err error)`              | 写入 Unicode 字符        | 写入字节数, 错误 | 处理多语言文本           |
    | `func (b *Writer) WriteString(s string) (int, error)`                   | 写入字符串               | 写入字节数, 错误 | 写入文本内容             |
    | `func (b *Writer) Flush() error`                                        | 刷新缓冲区到底层         | 错误            | 确保数据写入完成         |
    | `func (b *Writer) Available() int`                                      | 获取剩余缓冲区大小       | 字节数          | 检查缓冲区容量           |
    | `func (b *Writer) Buffered() int`                                       | 获取已缓冲字节数         | 字节数          | 检查待刷新数据量         |
    | `func (b *Writer) Reset(w io.Writer)`                                   | 重置 Writer 关联目标     | 无              | 重用 Writer 对象         |

    Scanner

            使用场景:

    • 按行处理文本文件

    • 解析结构化文本数据

    • 需要简单分割输入内容时

    | 方法签名                                                                 | 描述                     | 返回值          | 应用场景                 |
    |-------------------------------------------------------------------------|--------------------------|-----------------|--------------------------|
    | `func (s *Scanner) Scan() bool`                                         | 扫描下一个 token         | 是否扫描成功    | 迭代处理输入             |
    | `func (s *Scanner) Text() string`                                       | 获取扫描到的文本         | 字符串          | 获取当前 token 内容      |
    | `func (s *Scanner) Bytes() []byte`                                      | 获取扫描到的字节         | 字节切片        | 需要原始字节数据         |
    | `func (s *Scanner) Err() error`                                         | 获取扫描错误             | 错误            | 检查扫描过程错误         |
    | `func (s *Scanner) Split(split SplitFunc)`                              | 设置分割函数             | 无              | 自定义扫描逻辑           |
    | `func (s *Scanner) Buffer(buf []byte, max int)`                         | 设置缓冲区               | 无              | 处理大 token             |

    案例一、猜数游戏

    概述

            系统在一定范围内随机一个数据,让用户进行猜数,统计用户猜测次数,直到用户猜到数字结束程序。

    设计思路

    1. 生成一个随机数,用于让用户猜测。

    2. 设置一个死循环,用于持续读取用户数据。

    3. 将用户数据进行解析判断,看看是否等于目标值,并给出一定提示。

    代码

            写了两种读入方式,分别用Reader进行读入和用Scanner进行读入。

    package mainimport ("bufio""fmt""math/rand""os""strconv""time"
    )func main() {maxNum := 100rand.Seed(time.Now().UnixNano())secretNumber := rand.Intn(maxNum)//reader := bufio.NewReader(os.Stdin)sc := bufio.NewScanner(os.Stdin)fmt.Println("---猜数游戏已就绪----")cnt := 0for {cnt++fmt.Printf("第%v次猜数,你的选择是:\n", cnt)//a, err := reader.ReadString('\n')//if err != nil {//    fmt.Println("不可预知的错误")//    cnt--//    continue//}//a = strings.TrimSpace(a)a := sc.Scan()if sc.Err() != nil {fmt.Println("读取输入错误:", sc.Err())cnt--continue}guess, err := strconv.Atoi(sc.Text())if err != nil {fmt.Printf("'%v' 不是有效数字,请重新输入\n", a)cnt--continue}if guess == secretNumber {fmt.Printf("恭喜你,第%v次猜对了!\n", cnt)break} else if guess > secretNumber {fmt.Println("没猜对,猜大了")} else {fmt.Println("没猜对,猜小了")}}fmt.Println("Game Over")
    }
    

            需要注意的是:

    • 在测试的时候,如果编译器用到是vscode的话,不能使用那个自带的调试控制器,需要用终端进行测试。

    课后作业

            修改猜谜游戏中的最终代码,使用fmt.Scanf来简化代码实现

            就是换了一种读入的方式,感觉Go的读入方式还是比较玄学的,后续会开个新的文章将各种读取方式进行详解。

    package mainimport ("fmt""math/rand""time"
    )func main() {maxNum := 100rand.Seed(time.Now().UnixNano())secretNumber := rand.Intn(maxNum)fmt.Println("---猜数游戏已就绪----")cnt := 0for {cnt++fmt.Printf("第%v次猜数,你的选择是:\n", cnt)var guess int_, err := fmt.Scanf("%d", &guess)if err != nil {fmt.Println("输入无效!请输入数字")var discard stringfmt.Scanln(&discard)continue}fmt.Scanln()if guess == secretNumber {fmt.Printf("恭喜你,第%v次猜对了!\n", cnt)break} else if guess > secretNumber {fmt.Println("没猜对,猜大了")} else {fmt.Println("没猜对,猜小了")}}fmt.Println("Game Over")
    }
    

    案例二、在线词典

    概述

            设计一个在线词典用于翻译。

    设计思路

    1. 通过抓包的方式,抓取到一个在线翻译网站的API。

    2. 因为自己编写请求头比较麻烦,我们使用 https://curlconverter.com/go/这个网站可以将我们复制的 cURL bash直接转化成Go的代码。

    3. 然后查看请求的响应,我们需要对响应和请求进行一个封装,可以通过https://tool.lvtao.net/json2go网站对请求快速转化为Go的结构体。

    4. 然后编写基础代码进行query请求即可。

    代码

    package mainimport ("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 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)}req.Header.Set("Connection", "keep-alive")req.Header.Set("DNT", "1")req.Header.Set("os-version", "")req.Header.Set("sec-ch-ua-mobile", "?0")req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 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("device-id", "")req.Header.Set("os-type", "web")req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")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")req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")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 DictResponseerr = 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)}
    }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)
    }

    http://www.xdnf.cn/news/10345.html

    相关文章:

  • python打卡day42@浙大疏锦行
  • 动态库导出符号与extern “C“
  • 2025年05月总结及随笔之家电询价及以旧换新
  • 剪枝中的 `break` 与 `return` 区别详解
  • APM32主控键盘全功能开发实战教程:软件部分
  • 【论文解读】Deformable DETR | Deformable Transformers for End-to-End Object Detection
  • 题单:最大公约数(辗转相除法)
  • 安全漏洞修复导致SpringBoot2.7与Springfox不兼容
  • 爬虫工具链的详细分类解析
  • 力扣刷题Day 66:分割回文串(131)
  • 【Redis】数据类型补充
  • t018-高校宣讲会管理系统 【含源码!】
  • 浅谈简历制作的四点注意事项
  • NLP学习路线图(十四):词袋模型(Bag of Words)
  • Go语言中的数据类型转换
  • 数据结构之ArrayList
  • 【 SpringCloud | 微服务 网关 】
  • CppCon 2014 学习:Unicode in C++
  • win10手动调整日期和时间
  • ​​技术深度解析:《鸿蒙5.0+:无感续航的智能魔法》​
  • Java基本数据类型、抽象类和接口、枚举、时间类、String类全面介绍
  • 【PhysUnits】15.7 引入P1后的加法运算(add.rs)
  • 【赵渝强老师】OceanBase部署工具
  • buuctf-web
  • 计算机基础——宏病毒防御与网络技术
  • MacroDroid安卓版:自动化操作,让生活更智能
  • Ubuntu取消开机用户自动登录
  • RuoYi前后端分离框架实现前后端数据传输加密(二)之前端篇
  • 区块链可投会议CCF B--EDBT 2026 截止10.8 附录用率
  • unix/linux source 命令,其基本概念、定义、性质、定理