【Go】2、Go语言实战

article/2025/8/3 0:00:41

前言

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


前置知识

        本篇将涉及到一些在命令行的输入输出操作,之前我们已经学习了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.hkcw.cn/article/hyZJbfsCGZ.shtml

    相关文章

    基于Python与本地Ollama的智能语音唤醒助手实现

    项目简介 本项目是一个基于 Python 的智能语音助手,集成了语音录制、语音识别、AI对话和语音合成功能。用户可以通过语音与本地部署的 Ollama 大模型进行自然对话。 技术架构 核心功能模块 语音录制 - 使用 sounddevice 录制用户语音语音识别 - 使用 faster-whi…

    Vue框架2(vue搭建方式2:利用脚手架,ElementUI)

    一.引入vue第二种搭建方式 在以前的前端项目中,一个项目需要多个html文件实现页面之前的切换,如果页面中需要依赖js或者css文件,那么我们就需要在多个html文件中都需要导入vue.js文件,太过繁琐. 现在前端开发都采用单页面结果,一个项目中只有一个html文件 其他不同的内容都写…

    维斯塔潘谈和拉塞尔碰撞 意外相撞引发讨论

    在F1西班牙大奖赛正赛中,维斯塔潘因与拉塞尔相撞被罚时10秒,最终排名第十。赛后采访中,记者问及那次碰撞。维斯塔潘表示两人开车时确实撞到了一起。当记者指出他本可以避免这种情况时,维斯塔潘承认了这一点。至于为什么会发生这样的情况,他表示自己也不清楚。责任编辑:zx…

    乌称摧毁俄大量轰炸机 俄媒称系谣言 谎言蛛网

    俄罗斯“与假新闻作战”网站发布文章称,通过分析乌克兰方面发布的视频可以确认,乌总统泽连斯基所谓“已摧毁34%俄罗斯远程机队”的说法并不属实。俄方认为,乌方的行动更像是编织了一张“谎言蛛网”。俄方分析指出,乌克兰实际上可能仅摧毁了两架图-95战略轰炸机及一架安-12运…

    IntelliJ IDEA 接入 Ollama 本地模型 Qwen-coder

    一:下载ollama 官网下载https://ollama.com/ 二:安装 一键自动安装,且安装的是C盘 如果C盘紧张,想装在其他盘符,在安装包目录下打开cmd命令行, 在你想安装的盘下创建一个文件夹,例如在D盘创建…

    C++学习-入门到精通【12】文件处理

    C学习-入门到精通【12】文件处理 目录 C学习-入门到精通【12】文件处理一、文件和流二、创建顺序文件三、从顺序文件读取数据文件定位指针对之前的程序进行修改:贷款查询程序 四、更新顺序文件五、随机存取文件1.创建随机存取文件2.修改程序:贷款处理程序…

    生成式AI模型的重要评估指标——FID

    1、引言 随着深度学习的发展迅速,生成式模型如生成对抗网络(GAN)、变分自编码器(VAE)等取得了显著的进展。看似逼真的图像数据,仍旧会有结构缺陷等情况发生,那么如何客观、准确的评估这些生成式…

    第十:如何在Pycharm中安装AI插件(Proxy AI)

    一.安装插件 1.通过官网安装:https://plugins.jetbrains.com/plugin/21056-proxy-ai2.通过设置安装:设置->插件->搜索:Proxy AI->点击安装3.安装后重启二.配置插件 1.配置路径:设置 -> 工具 -> CodeGPT或者Proxy…

    在Visual Studio开发平台使用通义灵码:AI代码助手的深度实践指南

    引言:当经典IDE遇见AI代码革命 Visual Studio(以下简称VS)作为微软推出的旗舰级集成开发环境,长期占据企业级开发工具的核心地位。然而,在智能化浪潮下,传统IDE的代码编写效率瓶颈日益显现。阿里云推出的通…

    为什么你必须降AI?——写给每一位学生与科研人

    📉 为什么要降 AI 检测率?一篇文章带你看清真相! 随着AI大模型的发展,越来越多的人开始使用人工智能辅助写作,无论是撰写论文、文案,还是职称申请材料,都大大提升了效率。然而,随之…

    万字长文带你深度探索 MCP:AI 连接的未来之光​,MCP如何让AI产生“心灵感应“

    文章目录 一、引言:开启 MCP 的神秘大门​二、MCP 的基本概念解析​2.1 MCP 的定义与内涵​2.2 与传统协议的区别与优势​ 三、MCP 的技术原理深度剖析​3.1 核心技术架构​3.2 数据格式与通信协议​ 四、MCP 的应用案例全景展示​4.1 WhatsApp MCP:AI 助…

    【人工智能】人工智能的10大算法详解(优缺点+实际案例)

    人工智能(AI)是现代科技的重要领域,其中的算法是实现智能的核心。本文将介绍10种常见的人工智能算法,包括它们的原理、训练方法、优缺点及适用场景。 1. 线性回归(Linear Regression) 模型原理 线性回归…

    程序员鱼皮最新项目-----AI超级智能体教程(一)

    文章目录 1.前言1.什么是AI大模型2.什么是多模态3.阿里云百炼平台介绍3.1文本调试展示3.2阿里云和dashscope的关系3.3平台智能体应用3.4工作流的创建3.5智能体编排应用 1.前言 最近鱼皮大佬出了一套关于这个AI 的教程,关注鱼皮大佬很久了,鱼皮大佬确实在…

    Oracle官方MySQL+APEX+AI限时免费预约流程大全

    📢📢📢📣📣📣 作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…

    AI 高手之路 #6:Pandas 数据处理——AI 数据清洗与准备

    目录 引言:为什么 Pandas 是 AI 数据处理的瑞士军刀?Pandas 核心数据结构:精巧的矛与盾 2.1 Series:一维数据的精巧之矛 创建 Series:从零开始构建Series 索引和切片:精准定位与范围选取Series 运算:灵活的数据操作2.2 DataFrame:二维数据的坚实之盾 创建 DataFrame:构…

    初学者如何微调大模型?从0到1详解

    本文将手把手带你从0到1,详细解析初学者如何微调大模型,让你也能驾驭这些强大的AI工具。 1. 什么是大模型微调? 想象一下,预训练大模型就像一位博览群书但缺乏专业知识的通才。它掌握了海量的通用知识,但可能无法完美…

    2008-2023年 上市公司-企业研发操纵数据-社科经管实证数据

    2008-2023年上市公司-企业研发操纵数据-社科经管https://download.csdn.net/download/paofuluolijiang/90880455 https://download.csdn.net/download/paofuluolijiang/90880455 覆盖2008-2023年A股上市公司的研发操纵行为,累计包含超3.4万条观测值,涉及…

    马斯克:不想为美政府所做的一切担责 成裁员替罪羊

    当地时间6月1日,美国企业家埃隆马斯克在接受哥伦比亚广播公司采访时表达了他对政府的态度。他表示自己并不想公开反对美国政府,但也不愿意为政府所做的一切承担责任。马斯克提到,他领导的“政府效率部”成了所有问题的替罪羊,无论裁员是否真实发生,责任都被推到了该部门头…

    歼-10超低空飞行含金量超高 飞行员技术与胆识的双重考验

    歼-10战斗机是中国自主研制的高性能、多用途、全天候的第三代战斗机,能够完成震撼的超低空飞行。其动作流畅自如,如行云流水般展示挂载和低空盘旋等高难度动作。对于飞行员而言,利用山谷地形进行超低空飞行不仅有助于隐蔽行动,还能有效避开敌方雷达探测,实现突然袭击。尽管…

    F1西班牙站正赛:皮亚斯特里夺冠,迈凯伦领跑

    北京时间6月1日,F1西班牙大奖赛正赛结束。皮亚斯特里夺冠,诺里斯和勒克莱尔分别获得第二和第三名。拉塞尔、霍肯博格、汉密尔顿、哈贾尔、加斯利、阿隆索和维斯塔潘依次位列第四至第十名。安东内利和阿尔本因故退赛。比赛开始时,两台迈凯伦赛车占据头排位置,维斯塔潘和拉塞…