<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.7">Jekyll</generator><link href="http://172.19.0.16:8080/feed.xml" rel="self" type="application/atom+xml" /><link href="http://172.19.0.16:8080/" rel="alternate" type="text/html" /><updated>2026-03-06T20:48:10+08:00</updated><id>http://172.19.0.16:8080/feed.xml</id><title type="html">Gerry’s blog</title><subtitle>他山之石，可以攻玉</subtitle><author><name>gerryyang</name></author><entry><title type="html">Minimax in Action</title><link href="http://172.19.0.16:8080/ml/2026/02/28/minimax-in-action.html" rel="alternate" type="text/html" title="Minimax in Action" /><published>2026-02-28T12:30:00+08:00</published><updated>2026-02-28T12:30:00+08:00</updated><id>http://172.19.0.16:8080/ml/2026/02/28/minimax-in-action</id><content type="html" xml:base="http://172.19.0.16:8080/ml/2026/02/28/minimax-in-action.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#minimax&quot; id=&quot;markdown-toc-minimax&quot;&gt;MiniMax&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#在-claude-code-中使用-minimax-m21&quot; id=&quot;markdown-toc-在-claude-code-中使用-minimax-m21&quot;&gt;在 Claude Code 中使用 MiniMax-M2.1&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#安装-claude-code&quot; id=&quot;markdown-toc-安装-claude-code&quot;&gt;安装 Claude Code&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#获取-api-key&quot; id=&quot;markdown-toc-获取-api-key&quot;&gt;获取 API Key&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#coding-plan-api-key&quot; id=&quot;markdown-toc-coding-plan-api-key&quot;&gt;Coding Plan API Key&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#开放平台-api-key按量计费&quot; id=&quot;markdown-toc-开放平台-api-key按量计费&quot;&gt;开放平台 API Key（按量计费）&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置-minimax-api&quot; id=&quot;markdown-toc-配置-minimax-api&quot;&gt;配置 MiniMax API&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#安装-cc-switch&quot; id=&quot;markdown-toc-安装-cc-switch&quot;&gt;安装 cc-switch&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#申请-minimax-api-key&quot; id=&quot;markdown-toc-申请-minimax-api-key&quot;&gt;申请 MiniMax API Key&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#添加-minimax-配置&quot; id=&quot;markdown-toc-添加-minimax-配置&quot;&gt;添加 MiniMax 配置&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#配置模型名称&quot; id=&quot;markdown-toc-配置模型名称&quot;&gt;配置模型名称&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#启用配置&quot; id=&quot;markdown-toc-启用配置&quot;&gt;启用配置&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#启动-claude-code&quot; id=&quot;markdown-toc-启动-claude-code&quot;&gt;启动 Claude Code&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#信任文件夹&quot; id=&quot;markdown-toc-信任文件夹&quot;&gt;信任文件夹&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#执行-init-命令生成-claudemd&quot; id=&quot;markdown-toc-执行-init-命令生成-claudemd&quot;&gt;执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;/init&lt;/code&gt; 命令生成 &lt;code class=&quot;highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#claude-code-cli-的-bash-脚本包装器&quot; id=&quot;markdown-toc-claude-code-cli-的-bash-脚本包装器&quot;&gt;Claude Code CLI 的 Bash 脚本包装器&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#在-vs-code-使用-claude-code-生成网页时钟的测试&quot; id=&quot;markdown-toc-在-vs-code-使用-claude-code-生成网页时钟的测试&quot;&gt;在 VS Code 使用 Claude Code 生成网页时钟的测试&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#在-cursor-中使用-minimax-m21&quot; id=&quot;markdown-toc-在-cursor-中使用-minimax-m21&quot;&gt;在 Cursor 中使用 MiniMax-M2.1&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#安装-cursor&quot; id=&quot;markdown-toc-安装-cursor&quot;&gt;安装 Cursor&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#在-cursor-中配置-minimax-api&quot; id=&quot;markdown-toc-在-cursor-中配置-minimax-api&quot;&gt;在 Cursor 中配置 MiniMax API&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#在-cursor-中使用-minimax-m25&quot; id=&quot;markdown-toc-在-cursor-中使用-minimax-m25&quot;&gt;在 Cursor 中使用 MiniMax-M2.5&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#在-openclaw-中使用-minimax-m25&quot; id=&quot;markdown-toc-在-openclaw-中使用-minimax-m25&quot;&gt;在 OpenClaw 中使用 MiniMax-M2.5&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#打开配置设置&quot; id=&quot;markdown-toc-打开配置设置&quot;&gt;打开配置设置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#选择配置选项&quot; id=&quot;markdown-toc-选择配置选项&quot;&gt;选择配置选项&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#登陆授权&quot; id=&quot;markdown-toc-登陆授权&quot;&gt;登陆授权&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#确认模型选择&quot; id=&quot;markdown-toc-确认模型选择&quot;&gt;确认模型选择&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#重启-gateway-使配置生效&quot; id=&quot;markdown-toc-重启-gateway-使配置生效&quot;&gt;重启 gateway 使配置生效&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#测试对话&quot; id=&quot;markdown-toc-测试对话&quot;&gt;测试对话&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;minimax&quot;&gt;MiniMax&lt;/h1&gt;

&lt;p&gt;https://platform.minimaxi.com/subscribe/coding-plan&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc44.png&quot; alt=&quot;cc44&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc45.png&quot; alt=&quot;cc45&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;邀请码：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;🎁 MiniMax 跨年福利来袭！邀好友享 Coding Plan 双重好礼，助力开发体验！
好友立享 9折 专属优惠 + Builder 权益，你赢返利 + 社区特权！
👉 立即参与：https://platform.minimaxi.com/subscribe/coding-plan?code=5XvxeGS5Uv&amp;amp;source=link
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc46.png&quot; alt=&quot;cc46&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;在-claude-code-中使用-minimax-m21&quot;&gt;在 Claude Code 中使用 MiniMax-M2.1&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc0.png&quot; alt=&quot;cc0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;参考：https://platform.minimaxi.com/docs/guides/text-ai-coding-tools&lt;/p&gt;

&lt;p&gt;MiniMax-M2.1 &amp;amp; MiniMax-M2.1-lightning 兼容 OpenAI 和 Anthropic 接口协议，适用于代码助手、Agent 工具、AI IDE 等多种场景。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MiniMax 开放平台提供两种计费方案接入文本模型：Coding Plan 以及 按量计费。您可按照使用需求选择。调用计费模式取决于您所使用的 API Key，不同类型的 Key 将触发不同的计费方式。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc1.png&quot; alt=&quot;cc1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在 &lt;code class=&quot;highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt; 添加下面命令：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;unset &lt;/span&gt;ANTHROPIC_AUTH_TOKEN
&lt;span class=&quot;nb&quot;&gt;unset &lt;/span&gt;ANTHROPIC_BASE_URL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;安装-claude-code&quot;&gt;安装 Claude Code&lt;/h2&gt;

&lt;p&gt;可参考 &lt;a href=&quot;https://docs.claude.com/en/docs/claude-code/setup&quot;&gt;Claude Code 文档&lt;/a&gt; 进行安装。&lt;/p&gt;

&lt;h2 id=&quot;获取-api-key&quot;&gt;获取 API Key&lt;/h2&gt;

&lt;h3 id=&quot;coding-plan-api-key&quot;&gt;Coding Plan API Key&lt;/h3&gt;

&lt;p&gt;推荐您订阅 &lt;a href=&quot;https://platform.minimaxi.com/subscribe/coding-plan&quot;&gt;Coding Plan&lt;/a&gt;, 为用户的编程提升效率。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;访问 Coding Plan 选择最适合的编程套餐&lt;/li&gt;
  &lt;li&gt;前往 &lt;a href=&quot;https://platform.minimaxi.com/user-center/payment/coding-plan&quot;&gt;账户管理/Conding Plan&lt;/a&gt; 页面，查看订阅的 Coding Plan 套餐，并获得 Coding Plan 的 API Key，用于编程工具使用。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;开放平台-api-key按量计费&quot;&gt;开放平台 API Key（按量计费）&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;访问 &lt;a href=&quot;https://platform.minimaxi.com/user-center/basic-information/interface-key&quot;&gt;MiniMax 开放平台&lt;/a&gt; (国际用户可访问 &lt;a href=&quot;https://platform.minimax.io/user-center/basic-information/interface-key&quot;&gt;MiniMax Developer Platform&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;点击“&lt;strong&gt;创建新的密钥&lt;/strong&gt;”按钮，输入项目名称以创建新的 API Key&lt;/li&gt;
  &lt;li&gt;创建成功后，系统将展示 API Key。&lt;strong&gt;请务必复制并妥善保存，该密钥只会显示一次，无法再次查看&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;配置-minimax-api&quot;&gt;配置 MiniMax API&lt;/h2&gt;

&lt;h3 id=&quot;安装-cc-switch&quot;&gt;安装 cc-switch&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/farion1231/cc-switch&quot;&gt;cc-switch&lt;/a&gt; 是一个便捷的工具，可以快速切换 Claude Code 的 API 配置。&lt;/p&gt;

&lt;p&gt;macOS:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew tap farion1231/ccswitch
brew &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--cask&lt;/span&gt; cc-switch
brew upgrade &lt;span class=&quot;nt&quot;&gt;--cask&lt;/span&gt; cc-switch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Windows:&lt;/p&gt;

&lt;p&gt;前往 &lt;a href=&quot;https://github.com/farion1231/cc-switch/releases&quot;&gt;cc-switch GitHub Releases&lt;/a&gt; 页面下载最新版本的安装包。&lt;/p&gt;

&lt;p&gt;下载完成后启动 cc-switch 应用：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc2.png&quot; alt=&quot;cc2&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;申请-minimax-api-key&quot;&gt;申请 MiniMax API Key&lt;/h3&gt;

&lt;p&gt;需要通过绑定银行卡进行实名认证。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc4.png&quot; alt=&quot;cc4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc5.png&quot; alt=&quot;cc5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;https://platform.minimaxi.com/user-center/payment/balance&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc6.png&quot; alt=&quot;cc6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc7.png&quot; alt=&quot;cc7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc8.png&quot; alt=&quot;cc8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc9.png&quot; alt=&quot;cc9&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;添加-minimax-配置&quot;&gt;添加 MiniMax 配置&lt;/h3&gt;

&lt;p&gt;启动 cc-switch，点击右上角 ”+” ，选择预设的 MiniMax 供应商，并填写用户的 MiniMax API Key。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc3.png&quot; alt=&quot;cc3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc10.png&quot; alt=&quot;cc10&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;配置模型名称&quot;&gt;配置模型名称&lt;/h3&gt;

&lt;p&gt;将模型名称全部改为 MiniMax-M2.1，完成后点击右下角的 “添加”。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc12.png&quot; alt=&quot;cc12&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;启用配置&quot;&gt;启用配置&lt;/h3&gt;

&lt;p&gt;回到首页，点击 “启用” 即可开始使用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc11.png&quot; alt=&quot;cc11&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;启动-claude-code&quot;&gt;启动 Claude Code&lt;/h2&gt;

&lt;p&gt;配置完成后，进入工作目录，在终端中运行 &lt;code class=&quot;highlighter-rouge&quot;&gt;claude&lt;/code&gt; 命令以启动 Claude Code。&lt;/p&gt;

&lt;h2 id=&quot;信任文件夹&quot;&gt;信任文件夹&lt;/h2&gt;

&lt;p&gt;启动后，选择 信任此文件夹 (Trust This Folder)，以允许 Claude Code 访问该文件夹中的文件，随后开始在 Claude Code 中使用 MiniMax-M2.1。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc13.png&quot; alt=&quot;cc13&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc14.png&quot; alt=&quot;cc14&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc15.png&quot; alt=&quot;cc15&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;执行-init-命令生成-claudemd&quot;&gt;执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;/init&lt;/code&gt; 命令生成 &lt;code class=&quot;highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc18.png&quot; alt=&quot;cc18&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc19.png&quot; alt=&quot;cc19&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc20.png&quot; alt=&quot;cc20&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;claude-code-cli-的-bash-脚本包装器&quot;&gt;Claude Code CLI 的 Bash 脚本包装器&lt;/h2&gt;

&lt;p&gt;新建一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;claude-minimax&lt;/code&gt; 脚本，将从 MiniMax M2 官网获取的&lt;a href=&quot;https://platform.minimaxi.com/docs/api-reference/text-anthropic-api&quot;&gt;接口参数&lt;/a&gt;填入。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Claude Code CLI wrapper for MiniMax API&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Usage: ./claude-minimax [claude arguments]&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;CLAUDE_BIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/.local/bin/claude&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Set API credentials for MiniMax&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ANTHROPIC_AUTH_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Your Token&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ANTHROPIC_BASE_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://api.minimaxi.com/anthropic&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ANTHROPIC_MODEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MiniMax-M2&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;API_TIMEOUT_MS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3000000

&lt;span class=&quot;c&quot;&gt;# Optional: Use separate config directory&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CLAUDE_CONFIG_DIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/Tools/llm/claude/claude-minimax&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Execute Claude CLI with all passed arguments&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$CLAUDE_BIN&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;功能说明：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;设置 MiniMax API 的认证信息&lt;/li&gt;
  &lt;li&gt;指定使用 MiniMax-M2 模型&lt;/li&gt;
  &lt;li&gt;配置 API 超时时间为 3000000 毫秒（50分钟）&lt;/li&gt;
  &lt;li&gt;使用独立的配置目录避免与官方 Claude 配置冲突&lt;/li&gt;
  &lt;li&gt;将所有参数传递给原版 Claude CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;完成后，可以测试一下，看看能否正常运行。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;claude-minimax &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc22.png&quot; alt=&quot;cc22&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;在-vs-code-使用-claude-code-生成网页时钟的测试&quot;&gt;在 VS Code 使用 Claude Code 生成网页时钟的测试&lt;/h2&gt;

&lt;p&gt;第一步，新建一个本地目录作为项目目录，比如 &lt;code class=&quot;highlighter-rouge&quot;&gt;ai-clock&lt;/code&gt;。然后，在 VS Code 里面打开这个目录 &lt;code class=&quot;highlighter-rouge&quot;&gt;ai-clock&lt;/code&gt;，作为工作区。&lt;/p&gt;

&lt;p&gt;第二步，打开 VS Code 的菜单”终端/新建终端”，在这个终端窗口里面，输入 &lt;code class=&quot;highlighter-rouge&quot;&gt;claude-minimax&lt;/code&gt;。这时，窗口会提示你授予权限，同意后，就会进入主界面，大概就是下面这样。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc26.png&quot; alt=&quot;cc26&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc23.png&quot; alt=&quot;cc23&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc24.png&quot; alt=&quot;cc24&quot; /&gt;&lt;/p&gt;

&lt;p&gt;现在，我们就能在 VS Code 里面使用命令行的 Claude Code 了。这时，你既可以使用 IDE 编写代码，又可以通过命令行使用 AI 模型，兼得两者的优势。&lt;/p&gt;

&lt;p&gt;第三步，在 Claude Code 的提示符后面，输入 &lt;code class=&quot;highlighter-rouge&quot;&gt;/init&lt;/code&gt; 命令，用来在仓库里面生成一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; 文件，记录 AI 对这个仓库操作。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc25.png&quot; alt=&quot;cc25&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc27.png&quot; alt=&quot;cc27&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc28.png&quot; alt=&quot;cc28&quot; /&gt;&lt;/p&gt;

&lt;p&gt;由于示例仓库是空的，所以选择创建一个标准的 &lt;code class=&quot;highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; 模版文件。这个文件的作用是当作上下文，每次查询模型时，都会自动附上这个文件，以便模型了解代码库。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc29.png&quot; alt=&quot;cc29&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如果在提示框输入反斜杠，Claude Code 就会显示所有可用的命令。通过这些命令，我们就能使用 Claude Code 的强大功能，完成各种 AI 操作了。这一步是 Claude Code 的基础用法，对所有项目都是通用的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc30.png&quot; alt=&quot;cc30&quot; /&gt;&lt;/p&gt;

&lt;p&gt;第四步，在提示框输入前面的提示词（下图），让模型生成网页时钟。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Create HTML/CSS of an analog clock showing ${time}. Include numbers (or numerals) if you wish, and have a CSS animated second hand. Make it responsive and use a white background. Return ONLY the HTML/CSS code with no markdown formatting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;翻译成中文就是：”创建一个显示时间 ${time} 的模拟时钟的 HTML/CSS 代码。如果需要，可以包含数字，并添加 CSS 动画秒针。使其具有响应式设计，并使用白色背景。仅返回 HTML/CSS 代码，不要包含任何 Markdown 格式。”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc31.png&quot; alt=&quot;cc31&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc32.png&quot; alt=&quot;cc32&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/aiclock-minimax2.gif&quot; alt=&quot;aiclock-minimax2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;重新执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;/init&lt;/code&gt; 命令更新 &lt;code class=&quot;highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; 文件。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc34.png&quot; alt=&quot;cc34&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc35.png&quot; alt=&quot;cc35&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;在-cursor-中使用-minimax-m21&quot;&gt;&lt;a href=&quot;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-cursor-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2-1&quot;&gt;在 Cursor 中使用 MiniMax-M2.1&lt;/a&gt;&lt;/h1&gt;

&lt;h2 id=&quot;安装-cursor&quot;&gt;安装 Cursor&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;通过 &lt;a href=&quot;https://cursor.com/&quot;&gt;Cursor 官网&lt;/a&gt; 下载并安装 Cursor&lt;/li&gt;
  &lt;li&gt;打开 Cursor，右上角“设置”按钮，进入设置界面。点击“Sign in”按钮，登录自己的 Cursor 账户&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc37.png&quot; alt=&quot;cc37&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;在-cursor-中配置-minimax-api&quot;&gt;在 Cursor 中配置 MiniMax API&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc36.png&quot; alt=&quot;cc36&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;点击左侧栏的 “Models”，进入模型配置页面&lt;/li&gt;
  &lt;li&gt;展开 “API Keys” 部分，配置 API 信息：
    &lt;ul&gt;
      &lt;li&gt;勾选 “Override OpenAI Base URL”&lt;/li&gt;
      &lt;li&gt;在下方输入 MiniMax 的调用地址（国内用户使用 https://api.minimaxi.com/v1，国际用户使用 https://api.minimax.io/v1）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;在 OpenAI API Key 输入框，配置从 &lt;a href=&quot;https://platform.minimaxi.com/user-center/basic-information/interface-key&quot;&gt;MiniMax 开放平台&lt;/a&gt; (国际用户可访问 &lt;a href=&quot;https://platform.minimax.io/user-center/basic-information/interface-key&quot;&gt;MiniMax Developer Platform&lt;/a&gt;) 获取的 API Key&lt;/li&gt;
  &lt;li&gt;点击 “OpenAI API Key” 栏右侧的按钮，在弹出的窗口中点击 “Enable OpenAI API Key” 按钮，完成设置验证&lt;/li&gt;
  &lt;li&gt;在 Models 板块中，点击 “View All Models” 按钮，并点击 “Add Custom Model” 按钮&lt;/li&gt;
  &lt;li&gt;输入模型名称 “MiniMax-M2.1” 后，点击 “Add” 按钮&lt;/li&gt;
  &lt;li&gt;启用刚添加的 “MiniMax-M2.1” 模型&lt;/li&gt;
  &lt;li&gt;在聊天面板中选择 “MiniMax-M2.1” 模型，开始使用 “MiniMax-M2.1”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc40.png&quot; alt=&quot;cc40&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc41.png&quot; alt=&quot;cc41&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc42.png&quot; alt=&quot;cc42&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc38.png&quot; alt=&quot;cc38&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc39.png&quot; alt=&quot;cc39&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/cc43.png&quot; alt=&quot;cc43&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;在-cursor-中使用-minimax-m25&quot;&gt;&lt;a href=&quot;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-cursor-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2-5&quot;&gt;在 Cursor 中使用 MiniMax-M2.5&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;模型名改为 “MiniMax-M2.5”。其余方法参考 &lt;a href=&quot;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-cursor-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2-1&quot;&gt;在 Cursor 中使用 MiniMax-M2.1&lt;/a&gt;。&lt;/p&gt;

&lt;h1 id=&quot;在-openclaw-中使用-minimax-m25&quot;&gt;&lt;a href=&quot;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-openclaw-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2-5&quot;&gt;在 OpenClaw 中使用 MiniMax-M2.5&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;OpenClaw（原 Clawdbot） 是一个开源的 AI 助手，完全本地化，可以将各种消息平台与 AI 模型连接起来。它支持 WhatsApp、Telegram、Discord、iMessage 等多种平台，让您可以随时随地与 AI 助手对话。&lt;/p&gt;

&lt;p&gt;官方文档：&lt;a href=&quot;https://docs.openclaw.ai/start/getting-started&quot;&gt;OpenClaw 快速开始指南&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;配置 MiniMax 模型&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;推荐使用「一键安装 OAuth 并登录」的方式进行安装。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;下面是通过 OAuth 登录的配置方法。&lt;/p&gt;

&lt;h2 id=&quot;打开配置设置&quot;&gt;打开配置设置&lt;/h2&gt;

&lt;p&gt;如果 openclaw 的初始配置引导没有出现模型配置，则可以通过以下命令再次进行 openclaw 配置：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openclaw configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;选择配置选项&quot;&gt;选择配置选项&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Where will the Gateway run? → 选择 &lt;strong&gt;Local (this machine)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Select sections to configure → 选择 &lt;strong&gt;Model&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Model/auth provider → 选择 &lt;strong&gt;MiniMax&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;MiniMax auth method → 选择 &lt;strong&gt;MiniMax OAuth&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;MiniMax endpoint → 选择 &lt;strong&gt;CN&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw29.png&quot; alt=&quot;openclaw29&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;登陆授权&quot;&gt;登陆授权&lt;/h2&gt;

&lt;p&gt;登录并授权。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw30.png&quot; alt=&quot;openclaw30&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;确认模型选择&quot;&gt;确认模型选择&lt;/h2&gt;

&lt;p&gt;OAuth 登录完成后，进入模型选择。系统会默认勾选 minimax-portal/MiniMax-M2.1 和 minimax-portal/MiniMax-M2.5，并将 minimax-portal/MiniMax-M2.5 设为默认模型，可直接按回车确认使用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw31.png&quot; alt=&quot;openclaw31&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;重启-gateway-使配置生效&quot;&gt;重启 gateway 使配置生效&lt;/h2&gt;

&lt;p&gt;执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw gateway restart&lt;/code&gt; 重启 gateway 使得配置生效。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw27.png&quot; alt=&quot;openclaw27&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;测试对话&quot;&gt;测试对话&lt;/h2&gt;

&lt;p&gt;输入 &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw tui&lt;/code&gt;，若成功对话则表示配置成功。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw28.png&quot; alt=&quot;openclaw28&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;https://platform.minimaxi.com/user-center/payment/coding-plan&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools&quot;&gt;通过 AI 编程工具接入&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="ML" /><summary type="html"></summary></entry><entry><title type="html">OpenClaw - Personal AI Assistant</title><link href="http://172.19.0.16:8080/ml/2026/01/29/openclaw-in-action.html" rel="alternate" type="text/html" title="OpenClaw - Personal AI Assistant" /><published>2026-01-29T12:00:00+08:00</published><updated>2026-01-29T12:00:00+08:00</updated><id>http://172.19.0.16:8080/ml/2026/01/29/openclaw-in-action</id><content type="html" xml:base="http://172.19.0.16:8080/ml/2026/01/29/openclaw-in-action.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#快速开始&quot; id=&quot;markdown-toc-快速开始&quot;&gt;快速开始&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#使用示例&quot; id=&quot;markdown-toc-使用示例&quot;&gt;使用示例&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#在-tui-终端对话&quot; id=&quot;markdown-toc-在-tui-终端对话&quot;&gt;在 tui 终端对话&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#通过-qq-客户端对话&quot; id=&quot;markdown-toc-通过-qq-客户端对话&quot;&gt;通过 QQ 客户端对话&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置-http-服务&quot; id=&quot;markdown-toc-配置-http-服务&quot;&gt;配置 HTTP 服务&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#实现小游戏&quot; id=&quot;markdown-toc-实现小游戏&quot;&gt;实现小游戏&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#生成图片&quot; id=&quot;markdown-toc-生成图片&quot;&gt;生成图片&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#生成音乐&quot; id=&quot;markdown-toc-生成音乐&quot;&gt;生成音乐&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#生成视频&quot; id=&quot;markdown-toc-生成视频&quot;&gt;生成视频&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#skills-最佳实践&quot; id=&quot;markdown-toc-skills-最佳实践&quot;&gt;Skills 最佳实践&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#find-skills-发现其他好用的-skill&quot; id=&quot;markdown-toc-find-skills-发现其他好用的-skill&quot;&gt;Find Skills 发现其他好用的 Skill&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#clawsec-安全防护&quot; id=&quot;markdown-toc-clawsec-安全防护&quot;&gt;ClawSec 安全防护&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#self-improving-agent-ai-自我进化&quot; id=&quot;markdown-toc-self-improving-agent-ai-自我进化&quot;&gt;Self-Improving Agent AI 自我进化&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#tavily-web-search-让-ai-拥有实时信息获取能力&quot; id=&quot;markdown-toc-tavily-web-search-让-ai-拥有实时信息获取能力&quot;&gt;Tavily Web Search 让 AI 拥有实时信息获取能力&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#multi-search-engine-适合中文信息搜索&quot; id=&quot;markdown-toc-multi-search-engine-适合中文信息搜索&quot;&gt;Multi Search Engine 适合中文信息搜索&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#github-代码仓库的自然语言管理&quot; id=&quot;markdown-toc-github-代码仓库的自然语言管理&quot;&gt;GitHub 代码仓库的自然语言管理&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#proactive-agent-从被动相应到主动服务&quot; id=&quot;markdown-toc-proactive-agent-从被动相应到主动服务&quot;&gt;Proactive Agent 从被动相应到主动服务&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#debug-methodology-问题调试&quot; id=&quot;markdown-toc-debug-methodology-问题调试&quot;&gt;Debug Methodology 问题调试&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#skills-数据备份和恢复-重要&quot; id=&quot;markdown-toc-skills-数据备份和恢复-重要&quot;&gt;Skills 数据备份和恢复 (重要)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#背景介绍&quot; id=&quot;markdown-toc-背景介绍&quot;&gt;背景介绍&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#quick-start&quot; id=&quot;markdown-toc-quick-start&quot;&gt;Quick Start&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#moltbot-原-clawdbot&quot; id=&quot;markdown-toc-moltbot-原-clawdbot&quot;&gt;Moltbot (原 Clawdbot)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-it-does&quot; id=&quot;markdown-toc-what-it-does&quot;&gt;What It Does&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#works-with-everything&quot; id=&quot;markdown-toc-works-with-everything&quot;&gt;Works With Everything&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#install-the-cli-recommended&quot; id=&quot;markdown-toc-install-the-cli-recommended&quot;&gt;Install the CLI (recommended)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#uninstall&quot; id=&quot;markdown-toc-uninstall&quot;&gt;Uninstall&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#run-the-onboarding-wizard-and-install-the-service&quot; id=&quot;markdown-toc-run-the-onboarding-wizard-and-install-the-service&quot;&gt;Run the onboarding wizard (and install the service)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#auth-where-it-lives-important&quot; id=&quot;markdown-toc-auth-where-it-lives-important&quot;&gt;Auth: where it lives (important)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#start-the-gateway&quot; id=&quot;markdown-toc-start-the-gateway&quot;&gt;Start the Gateway&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#quick-verify-2-min&quot; id=&quot;markdown-toc-quick-verify-2-min&quot;&gt;Quick verify (2 min)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#channles&quot; id=&quot;markdown-toc-channles&quot;&gt;Channles&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#imessage&quot; id=&quot;markdown-toc-imessage&quot;&gt;Imessage&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#quick-setup-beginner&quot; id=&quot;markdown-toc-quick-setup-beginner&quot;&gt;Quick setup (beginner)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#使用-lighthouse-部署-openclaw-全能助手&quot; id=&quot;markdown-toc-使用-lighthouse-部署-openclaw-全能助手&quot;&gt;使用 lighthouse 部署 OpenClaw 全能助手&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#购买-openclaw-云服务&quot; id=&quot;markdown-toc-购买-openclaw-云服务&quot;&gt;购买 OpenClaw 云服务&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置-openclaw&quot; id=&quot;markdown-toc-配置-openclaw&quot;&gt;配置 OpenClaw&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#qq开放平台申请机器人&quot; id=&quot;markdown-toc-qq开放平台申请机器人&quot;&gt;QQ开放平台申请机器人&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#web-search-能力&quot; id=&quot;markdown-toc-web-search-能力&quot;&gt;Web Search 能力&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#配置-brave-api-收费&quot; id=&quot;markdown-toc-配置-brave-api-收费&quot;&gt;配置 Brave API (收费)&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#配置-finnhub-免费&quot; id=&quot;markdown-toc-配置-finnhub-免费&quot;&gt;配置 finnhub (免费)&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#配置-tavily-免费&quot; id=&quot;markdown-toc-配置-tavily-免费&quot;&gt;配置 tavily (免费)&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#更多用法&quot; id=&quot;markdown-toc-更多用法&quot;&gt;更多用法&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#常用命令&quot; id=&quot;markdown-toc-常用命令&quot;&gt;常用命令&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#打开终端&quot; id=&quot;markdown-toc-打开终端&quot;&gt;打开终端&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看帮助&quot; id=&quot;markdown-toc-查看帮助&quot;&gt;查看帮助&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#初始化配置&quot; id=&quot;markdown-toc-初始化配置&quot;&gt;初始化配置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置向导&quot; id=&quot;markdown-toc-配置向导&quot;&gt;配置向导&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看配置&quot; id=&quot;markdown-toc-查看配置&quot;&gt;查看配置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#设置配置&quot; id=&quot;markdown-toc-设置配置&quot;&gt;设置配置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#启动停止-gateway&quot; id=&quot;markdown-toc-启动停止-gateway&quot;&gt;启动/停止 Gateway&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#运行时-gateway&quot; id=&quot;markdown-toc-运行时-gateway&quot;&gt;运行时 Gateway&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看日志&quot; id=&quot;markdown-toc-查看日志&quot;&gt;查看日志&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#创建新的会话-清空-token-上下文&quot; id=&quot;markdown-toc-创建新的会话-清空-token-上下文&quot;&gt;创建新的会话 (清空 token 上下文)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#系统服务管理&quot; id=&quot;markdown-toc-系统服务管理&quot;&gt;系统服务管理&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#发送消息&quot; id=&quot;markdown-toc-发送消息&quot;&gt;发送消息&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#发送媒体文件&quot; id=&quot;markdown-toc-发送媒体文件&quot;&gt;发送媒体文件&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看技能列表&quot; id=&quot;markdown-toc-查看技能列表&quot;&gt;查看技能列表&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#安装卸载技能&quot; id=&quot;markdown-toc-安装卸载技能&quot;&gt;安装/卸载技能&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#更新技能&quot; id=&quot;markdown-toc-更新技能&quot;&gt;更新技能&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#技能开发&quot; id=&quot;markdown-toc-技能开发&quot;&gt;技能开发&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看频道&quot; id=&quot;markdown-toc-查看频道&quot;&gt;查看频道&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#登录频道&quot; id=&quot;markdown-toc-登录频道&quot;&gt;登录频道&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#频道测试&quot; id=&quot;markdown-toc-频道测试&quot;&gt;频道测试&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#频道配置&quot; id=&quot;markdown-toc-频道配置&quot;&gt;频道配置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看会话&quot; id=&quot;markdown-toc-查看会话&quot;&gt;查看会话&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#会话操作&quot; id=&quot;markdown-toc-会话操作&quot;&gt;会话操作&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看节点&quot; id=&quot;markdown-toc-查看节点&quot;&gt;查看节点&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#节点操作&quot; id=&quot;markdown-toc-节点操作&quot;&gt;节点操作&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#搜索记忆&quot; id=&quot;markdown-toc-搜索记忆&quot;&gt;搜索记忆&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#记忆操作&quot; id=&quot;markdown-toc-记忆操作&quot;&gt;记忆操作&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#查看-cron-任务&quot; id=&quot;markdown-toc-查看-cron-任务&quot;&gt;查看 Cron 任务&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#创建-cron-任务&quot; id=&quot;markdown-toc-创建-cron-任务&quot;&gt;创建 Cron 任务&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cron-任务操作&quot; id=&quot;markdown-toc-cron-任务操作&quot;&gt;Cron 任务操作&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#健康检查&quot; id=&quot;markdown-toc-健康检查&quot;&gt;健康检查&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#系统状态&quot; id=&quot;markdown-toc-系统状态&quot;&gt;系统状态&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#安全检查&quot; id=&quot;markdown-toc-安全检查&quot;&gt;安全检查&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#更新-openclaw&quot; id=&quot;markdown-toc-更新-openclaw&quot;&gt;更新 OpenClaw&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#qa&quot; id=&quot;markdown-toc-qa&quot;&gt;Q&amp;amp;A&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#minimax-接口配置&quot; id=&quot;markdown-toc-minimax-接口配置&quot;&gt;MiniMax 接口配置&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#升级-openclaw-版本之后用户之前安装的-skill-失效了&quot; id=&quot;markdown-toc-升级-openclaw-版本之后用户之前安装的-skill-失效了&quot;&gt;升级 openclaw 版本之后用户之前安装的 skill 失效了&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#gateway-异常修复&quot; id=&quot;markdown-toc-gateway-异常修复&quot;&gt;gateway 异常修复&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#link-channel-unknown-错误&quot; id=&quot;markdown-toc-link-channel-unknown-错误&quot;&gt;Link channel: unknown 错误&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;快速开始&quot;&gt;快速开始&lt;/h1&gt;

&lt;p&gt;官方文档：&lt;a href=&quot;https://docs.openclaw.ai/start/getting-started&quot;&gt;OpenClaw 快速开始指南&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw0.png&quot; alt=&quot;openclaw0&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;使用示例&quot;&gt;使用示例&lt;/h1&gt;

&lt;h2 id=&quot;在-tui-终端对话&quot;&gt;在 tui 终端对话&lt;/h2&gt;

&lt;p&gt;运行 &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw tui&lt;/code&gt; 命令后进行对话。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw1.png&quot; alt=&quot;openclaw1&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;通过-qq-客户端对话&quot;&gt;通过 QQ 客户端对话&lt;/h2&gt;

&lt;p&gt;创建 QQ Channel 并绑定到 QQbot，然后在 QQ 客户端与 QQbot 进行对话。&lt;/p&gt;

&lt;p&gt;注册的 QQbot 信息：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw2.png&quot; alt=&quot;openclaw2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;通过 QQbot 查看具备的 Skills 能力：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw3.png&quot; alt=&quot;openclaw3&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;配置-http-服务&quot;&gt;配置 HTTP 服务&lt;/h2&gt;

&lt;p&gt;通过 openclaw 配置一个常驻的 HTTP 服务（可以指定数据访问的目录和端口），可方便通过 Web 浏览器查看和下载 openclaw 在云服务器上生成的文件。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 数据访问目录&lt;/span&gt;
/root/.openclaw/workspace/data

&lt;span class=&quot;c&quot;&gt;# 服务访问端口&lt;/span&gt;
8080
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 openclaw 创建完 HTTP 服务后，再在腾讯云控制台通过 AI 助手完成网络访问策略的配置：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw36.png&quot; alt=&quot;openclaw36&quot; /&gt;&lt;/p&gt;

&lt;p&gt;通过浏览器测试访问成功：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw37.png&quot; alt=&quot;openclaw37&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw38.png&quot; alt=&quot;openclaw38&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw39.png&quot; alt=&quot;openclaw39&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;实现小游戏&quot;&gt;实现小游戏&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw4.png&quot; alt=&quot;openclaw4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw46.png&quot; alt=&quot;openclaw46&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;生成图片&quot;&gt;生成图片&lt;/h2&gt;

&lt;p&gt;单独聊天：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw34.png&quot; alt=&quot;openclaw34&quot; /&gt;&lt;/p&gt;

&lt;p&gt;QQ群聊天：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw35.png&quot; alt=&quot;openclaw35&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;生成音乐&quot;&gt;生成音乐&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw43.png&quot; alt=&quot;openclaw43&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw44.png&quot; alt=&quot;openclaw44&quot; /&gt;&lt;/p&gt;

&lt;p&gt;http://106.55.160.81:8080/song.mp3&lt;/p&gt;

&lt;h2 id=&quot;生成视频&quot;&gt;生成视频&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw47.png&quot; alt=&quot;openclaw47&quot; /&gt;&lt;/p&gt;

&lt;p&gt;http://106.55.160.81:8080/cat_dance_1772715932.mp4&lt;/p&gt;

&lt;h1 id=&quot;skills-最佳实践&quot;&gt;Skills 最佳实践&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;skills 中不能记录敏感信息防止泄漏，例如：LLM API Key 的信息，应该将 API Key 的信息配置在服务器独立的配置文件中，例如：&lt;code class=&quot;highlighter-rouge&quot;&gt;/root/.openclaw/workspace/.config/api-keys.json&lt;/code&gt;，并只有服务器用户有查看权限。可以通过增加一个 security skill 来保证所需的安全约束。&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;openclaw 通过 &lt;code class=&quot;highlighter-rouge&quot;&gt;/root/.openclaw/workspace/TOOLS.md&lt;/code&gt; 记录可以使用的 skills 技能，增删 skills 目录下的技能描述后，也需要同步更新 &lt;code class=&quot;highlighter-rouge&quot;&gt;TOOLS.md&lt;/code&gt; 文件。&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;通过 &lt;a href=&quot;https://clawhub.ai/&quot;&gt;ClawHub&lt;/a&gt; 安装所需的 skills。&lt;/p&gt;

&lt;p&gt;以安装 &lt;code class=&quot;highlighter-rouge&quot;&gt;self-improving-agent&lt;/code&gt; 为例，可以使用以下的方法安装：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install any skill folder in one shot: &lt;code class=&quot;highlighter-rouge&quot;&gt;npx clawhub@latest install your_skill_name&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;或者在 ClawHub 页面直接下载，https://wry-manatee-359.convex.site/api/v1/download?slug=self-improving-agent。&lt;/li&gt;
  &lt;li&gt;或者执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;clawdhub install self-improving-agent&lt;/code&gt; 命令。&lt;/li&gt;
  &lt;li&gt;也可以直接告诉 openclaw 让它来安装，例如：通过 https://clawhub.ai/ 安装 self-improving-agent 这个 skill。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw41.png&quot; alt=&quot;openclaw41&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;find-skills-发现其他好用的-skill&quot;&gt;&lt;a href=&quot;https://clawhub.ai/JimLiuxinghai/find-skills&quot;&gt;Find Skills&lt;/a&gt; 发现其他好用的 Skill&lt;/h2&gt;

&lt;p&gt;Helps users discover and install agent skills when they ask questions like “how do I do X”, “find a skill for X”, “is there a skill that can…”, or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用场景：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;你想做某件事，但不知道有没有对应的 Skill。例如：想做小红书图片，可以直接让 openclaw 帮你找个适合做小红书图片的技能。然后 openclaw 会根据搜索结果选择一个合适的技能。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;实现原理：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;接收你的需求描述&lt;/li&gt;
  &lt;li&gt;向 ClawHub 发起搜索请求&lt;/li&gt;
  &lt;li&gt;对比不同 Skills 的匹配速度&lt;/li&gt;
  &lt;li&gt;推荐合适的选择&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;clawsec-安全防护&quot;&gt;&lt;a href=&quot;https://clawhub.ai/chrisochrisochriso-cmyk/clawsec&quot;&gt;ClawSec&lt;/a&gt; 安全防护&lt;/h2&gt;

&lt;p&gt;Manage and operate ClawSec Monitor v3.0, a MITM HTTP/HTTPS proxy that logs AI agent traffic, detects exfiltration and injection threats in real time.&lt;/p&gt;

&lt;h2 id=&quot;self-improving-agent-ai-自我进化&quot;&gt;&lt;a href=&quot;https://clawhub.ai/pskoett/self-improving-agent&quot;&gt;Self-Improving Agent&lt;/a&gt; AI 自我进化&lt;/h2&gt;

&lt;p&gt;Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Clau…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;核心思想：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;让 Agent 记住自己的错误，学到的东西，用户的纠正，并在后续会话中自动参考。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;实现原理：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;自动监控。监听命令执行结果，用户反馈&lt;/li&gt;
  &lt;li&gt;结构化记录。将学习内容记录在 &lt;code class=&quot;highlighter-rouge&quot;&gt;.learnings/&lt;/code&gt; 目录下的日志文件中。每条学习记录包括：ID，时间戳，优先级，摘要，复现步骤，建议修复方案&lt;/li&gt;
  &lt;li&gt;智能检索。遇到类似问题时，自动查询历史记录&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;tavily-web-search-让-ai-拥有实时信息获取能力&quot;&gt;&lt;a href=&quot;https://clawhub.ai/arun-8687/tavily-search&quot;&gt;Tavily Web Search&lt;/a&gt; 让 AI 拥有实时信息获取能力&lt;/h2&gt;

&lt;p&gt;AI-optimized web search via Tavily API. Returns concise, relevant results for AI agents.&lt;/p&gt;

&lt;h2 id=&quot;multi-search-engine-适合中文信息搜索&quot;&gt;&lt;a href=&quot;https://clawhub.ai/gpyAngyoujun/multi-search-engine&quot;&gt;Multi Search Engine&lt;/a&gt; 适合中文信息搜索&lt;/h2&gt;

&lt;p&gt;Multi search engine integration with 17 engines (8 CN + 9 Global). Supports advanced search operators, time filters, site search, privacy engines, and WolframAlpha knowledge queries. No API keys required.&lt;/p&gt;

&lt;h2 id=&quot;github-代码仓库的自然语言管理&quot;&gt;&lt;a href=&quot;https://clawhub.ai/steipete/github&quot;&gt;GitHub&lt;/a&gt; 代码仓库的自然语言管理&lt;/h2&gt;

&lt;p&gt;Interact with GitHub using the &lt;code class=&quot;highlighter-rouge&quot;&gt;gh&lt;/code&gt; CLI. Use &lt;code class=&quot;highlighter-rouge&quot;&gt;gh issue&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;gh pr&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;gh run&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;gh api&lt;/code&gt; for issues, PRs, CI runs, and advanced queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用场景：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub Skill 通过集成 GitHub CLI 命令行工具（gh 命令行工具），让你可以用自然语言管理 GitHub 仓库。&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;搜索开源项目：搜索 Python 爬虫相关的热门仓库。&lt;/li&gt;
  &lt;li&gt;管理 Issue：查看某仓库的高优先级 Issue。&lt;/li&gt;
  &lt;li&gt;代码审查：查看最新的 PR 有没有问题。&lt;/li&gt;
  &lt;li&gt;自动化报告：生成本周项目进展报告。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;实现原理：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;理解用户的自然语言指令&lt;/li&gt;
  &lt;li&gt;转换为对应的 gh 命令&lt;/li&gt;
  &lt;li&gt;执行并返回结果&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;proactive-agent-从被动相应到主动服务&quot;&gt;&lt;a href=&quot;https://clawhub.ai/halthelobster/proactive-agent&quot;&gt;Proactive Agent&lt;/a&gt; 从被动相应到主动服务&lt;/h2&gt;

&lt;p&gt;Transform AI agents from task-followers into proactive partners that anticipate needs and continuously improve. Now with WAL Protocol, Working Buffer, Autonomous Crons, and battle-tested patterns. Part of the Hal Stack 🦞&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;使用场景：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;让 openclaw 主动跟踪一个项目的学习进度。例如，每周五自动汇总学习成果，并主动推荐下周的学习计划。这种从“被动执行”到“主动服务”的转变，让 AI 更像一个真正的助理。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;实现原理：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;心跳机制。每15分钟自动唤醒&lt;/li&gt;
  &lt;li&gt;任务监控。持续跟踪进行中的任务&lt;/li&gt;
  &lt;li&gt;自我迭代。优化工作流程&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;debug-methodology-问题调试&quot;&gt;&lt;a href=&quot;https://clawhub.ai/abczsl520/debug-methodology&quot;&gt;Debug Methodology&lt;/a&gt; 问题调试&lt;/h2&gt;

&lt;p&gt;Systematic debugging and problem-solving methodology. Activate when encountering unexpected errors, service failures, regression bugs, deployment issues, or…&lt;/p&gt;

&lt;h1 id=&quot;skills-数据备份和恢复-重要&quot;&gt;Skills 数据备份和恢复 (重要)&lt;/h1&gt;

&lt;p&gt;openclaw 保存 Skills 的目录是 &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.openclaw/workspace/skills/&lt;/code&gt;，在保证 Skills 中不存在敏感信息泄漏的情况下，可以将 skills 使用 git 来维护，也可以方便其他场景复用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw40.png&quot; alt=&quot;openclaw40&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw42.png&quot; alt=&quot;openclaw42&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;背景介绍&quot;&gt;背景介绍&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;命名变化：ClawBot -&amp;gt; MoltBot -&amp;gt; OpenClaw&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;可以拓展想象：你买了一台新电脑，里面有一个“幽灵实体”，你把键盘、鼠标和网络权限交给它，把它当成一个虚拟同事。你可以直接跟它说话，交代事情。凡是你能在电脑上做的事，这个 Agent 理论上都能替你完成。这就是它真正强大的地方。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;个人 AI 助手 &lt;strong&gt;Clawdbot&lt;/strong&gt; 席卷硅谷，国内外社交平台上全是关于它的讨论。不过，项目创始人 &lt;strong&gt;Peter Steinberger&lt;/strong&gt; 在 X 平台上发文表示，他被 Anthropic 强制要求更改名称的成 &lt;strong&gt;Moltbot&lt;/strong&gt;，这并非他本人的决定。这次改名源于商标问题，但在操作过程中不仅搞砸了 GitHub 的账号更名，连 X 平台的原账号名也被加密货币推广者抢注了。最终，他的新账号名定为 &lt;code class=&quot;highlighter-rouge&quot;&gt;@moltbot&lt;/code&gt;。使用 &lt;strong&gt;Clawdbot&lt;/strong&gt; 后，网友们纷纷给出了很高的评价。“&lt;strong&gt;它是迄今为止最伟大的 AI 应用，相当于你 24 小时全天候专属 AI 员工&lt;/strong&gt;”。Creator Buddy 创始人兼 CEO Alex Finn 盛赞道，“&lt;strong&gt;这就是他们 (Anthropic) 希望 Claude Cowork 呈现的样子&lt;/strong&gt;”。当前，ClawdBot 项目已经开源：https://github.com/clawdbot/clawdbot。&lt;/p&gt;

&lt;p&gt;Alex 展示了给他的 Clawdbot 发信息，让它帮其预订下周六在一家餐厅的座位。当 OpenTable 预订失败时，Clawdbot 利用 ElevenLabs 的技术致电餐厅并完成了预订。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot21.png&quot; alt=&quot;moltbot21&quot; /&gt;&lt;/p&gt;

&lt;p&gt;但 Clawdbot 真正让技术圈兴奋的，并不只是“能干活” ，而是其协作方式极其激进：不会写代码的人，也能直接提 PR。&lt;strong&gt;原因很简单：它几乎是 100% 用 AI 写出来的&lt;/strong&gt;，PR 在这里更像是“我遇到了这个问题”，而不是“我写了一段多漂亮的代码”。更有意思的是，这个看似“全开源”的项目，偏偏故意留了一点不开源。创始人 Peter Steinberger 保留了一个名为“soul”的文件只占项目的 0.00001%。他说得很直白：这既是他的”秘密资产”，也是一个刻意留下来的安全靶子。大家真的在试着 hack 它，他就等着看模型到底守不守得住。到目前为止，“soul”还没被偷出来。作为忠实粉丝，Alex 表示这是自 Claude Code 发布以来，自己第一次连续两天没有用它。但是他的 Clawdbot Henry 已经连续 48 小时不停地 Vibe Coding。“&lt;strong&gt;我这辈子都没写过这么多代码。Vibe Coding 已死，Vibe Orchestration 已来。&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;现在，Alex 想要退掉 Mac Mini，换一台价值 1 万美元的 Mac Studio。“我的 Clawdbot Henry 将控制一台人工智能超级计算机。Henry 将使用 Opus 作为大脑，并使用多个本地模型作为员工集群。” &lt;strong&gt;Clawbot 并不是传统意义上只能回答问题的聊天机器人，它本质上是一个持续运行、可以执行任务的个人 AI 智能体&lt;/strong&gt;。你可以把它安装在自己的设备上，如 Mac、Windows、Linux，&lt;strong&gt;它可以长期在线，不停地接收指令、处理任务、记住你的偏好和历史对话，随着时间积累变得更懂你、更有“记忆”&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;总的来说，&lt;strong&gt;Clawbot 最令人震撼的地方有三点&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;它几乎可以完全控制你的电脑&lt;/strong&gt;。它没有传统意义上的“护栏”，不局限在某几个功能里，而是可以像一个真正坐在电脑前的人一样，操作你电脑上的一切。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;它拥有近乎无限的长期记忆&lt;/strong&gt;。Clawbot 内置了一套非常复杂的记忆系统。说过的话、做过的事，都会不断被记录下来。每次对话结束后，它都会自动总结聊过的内容，并把关键信息提取出来，存进长期记忆中。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;它完全通过聊天应用来交互&lt;/strong&gt;。你平时用哪些聊天工具，Clawbot 就能在哪儿跟你对话，这意味着，只要打开一个聊天软件，就可以通过一条消息把任务交给 Clawbot 去做。现在 Clawbot 支持 WhatsApp、Telegram、Slack、Discord、Google Chat、Signal、iMessage、Microsoft Teams、WebChat 等，还有 BlueBubbles、Matrix、Zalo 以及 Zalo Personal。&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;不过，如此放开的权限让其几乎没有护栏，这带来很大的安全隐患，现在 GitHub 上有 500 多个安全的问题，这也让部分网友望而却步。对此，很多使用过的用户几乎都表示，不建议一开始就把 Clawbot 装在主力电脑上。“在你还不熟悉它之前，把它放在一个独立环境里是最安全的选择。”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot22.png&quot; alt=&quot;moltbot22&quot; /&gt;&lt;/p&gt;

&lt;p&gt;不过大家没有想到，这个 AI 员工首先带火的竟然是 &lt;strong&gt;Mac Mini&lt;/strong&gt;。很多人为了运行 Clawdbot 会专门买一台电脑，而大部分选择了 Mac Mini，原因是它便宜、兼容好、功率低、安静、占地小。谷歌 DeepMind 产品经理 Logan Kilpatrick 都忍不住订了台 Mac Mini。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot23.png&quot; alt=&quot;moltbot23&quot; /&gt;&lt;/p&gt;

&lt;p&gt;更有网友晒出自己一口气买了 40 台 Mac mini 来运行 Clawdbot。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot24.png&quot; alt=&quot;moltbot24&quot; /&gt;&lt;/p&gt;

&lt;p&gt;但也有网友称可以用一台免费的服务器运行着完全一样的程序，Alex 也称没必要花 600 美元买 Mac mini，有其他便宜得多的方式来运行 Clawbot。买 Mac mini 更多是个人偏好，而不是技术上的必要条件。你完全可以不买任何硬件，只需要一个 VPS。另外，云厂商们动作迅速，有网友发现腾讯云直接推出了 Clawbot 云服务。&lt;/p&gt;

&lt;p&gt;随着项目的火爆，其背后的开发者 Peter Steinberger 也备受关注。Peter 在“Open Source Friday”上分享了他一手打造 Clawdbot 的经过，从创建、创始到维护，全由他独自完成。有意思的是，此前甚至有传言称，Peter 可能是一个 bot、Agent，甚至本身就是 AI。而 Peter 的出现也让项目成员和关注者们确认了他是个“真人”。Peter 一度已经退休了，后来又从退休状态里出来开始折腾 AI。从外表来看，Peter 年轻有活力，完全不像已到退休年龄、可领取养老金的人。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot25.png&quot; alt=&quot;moltbot25&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h1&gt;

&lt;p&gt;Fastest chat: open the Control UI (no channel setup needed). Run &lt;code class=&quot;highlighter-rouge&quot;&gt;moltbot dashboard (PS: 找不到 moltbot 命令可使用 clawdbot 替换，建议将 moltbot 设置为 clawdbot 命令的别名)&lt;/code&gt; and chat in the browser, or open &lt;code class=&quot;highlighter-rouge&quot;&gt;http://127.0.0.1:18789/&lt;/code&gt; on the gateway host. Docs: &lt;a href=&quot;https://docs.molt.bot/web/dashboard&quot;&gt;Dashboard&lt;/a&gt; and &lt;a href=&quot;https://docs.molt.bot/web/control-ui&quot;&gt;Control UI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recommended path: use the &lt;strong&gt;CLI onboarding wizard&lt;/strong&gt; (&lt;code class=&quot;highlighter-rouge&quot;&gt;moltbot onboard&lt;/code&gt;). It sets up:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;model/auth (OAuth recommended)&lt;/li&gt;
  &lt;li&gt;gateway settings&lt;/li&gt;
  &lt;li&gt;channels (WhatsApp/Telegram/Discord/Mattermost (plugin)/…)&lt;/li&gt;
  &lt;li&gt;pairing defaults (secure DMs)&lt;/li&gt;
  &lt;li&gt;workspace bootstrap + skills&lt;/li&gt;
  &lt;li&gt;optional background service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want the deeper reference pages, jump to: &lt;a href=&quot;https://docs.molt.bot/start/wizard&quot;&gt;Wizard&lt;/a&gt;, &lt;a href=&quot;https://docs.molt.bot/start/setup&quot;&gt;Setup&lt;/a&gt;, &lt;a href=&quot;https://docs.molt.bot/start/pairing&quot;&gt;Pairing&lt;/a&gt;, &lt;a href=&quot;https://docs.molt.bot/gateway/security&quot;&gt;Security&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot27.png&quot; alt=&quot;moltbot27&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot28.png&quot; alt=&quot;moltbot28&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;moltbot-原-clawdbot&quot;&gt;Moltbot (原 Clawdbot)&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/moltbot/moltbot&quot;&gt;Moltbot&lt;/a&gt; is a personal AI assistant you run on your own devices. It answers you on the channels you already use (WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, Microsoft Teams, WebChat), plus extension channels like BlueBubbles, Matrix, Zalo, and Zalo Personal. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.&lt;/p&gt;

&lt;p&gt;If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot1.png&quot; alt=&quot;moltbot1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot2.png&quot; alt=&quot;moltbot2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot19.png&quot; alt=&quot;moltbot19&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot20.png&quot; alt=&quot;moltbot20&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;what-it-does&quot;&gt;What It Does&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs on Your Machine&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Mac, Windows, or Linux. Anthropic, OpenAI, or local models. Private by default - your data stays yours.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Any Chat App&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Talk to it on WhatsApp, Telegram, Discord, Slack, Sigal, or iMessage. Works in DMs and group chats.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Persistent Memory&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Remembers you and becomes uniquely yours. Your preferences, your context, your AI.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Browser Control&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;It can browse the web, fill forms, and extract data from any site.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Full System Access&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Read and write files, run shell commands, execute scripts. Full access or sandboxed - your choice.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Skills &amp;amp; Plugins&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Extend with community skills or build your own. It can even write its own.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;works-with-everything&quot;&gt;Works With Everything&lt;/h1&gt;

&lt;p&gt;See https://www.molt.bot/integrations.&lt;/p&gt;

&lt;h1 id=&quot;install-the-cli-recommended&quot;&gt;Install the CLI (recommended)&lt;/h1&gt;

&lt;p&gt;Works on macOS, Windows &amp;amp; Linux. The one-liner installs &lt;code class=&quot;highlighter-rouge&quot;&gt;Node.js&lt;/code&gt; and everything else for you.&lt;/p&gt;

&lt;p&gt;Runtime: &lt;strong&gt;Node ≥22&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# install.sh&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://molt.bot/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The wizard installs the Gateway daemon (launchd/systemd user service) so it stays running. &lt;strong&gt;Legacy note&lt;/strong&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;clawdbot&lt;/code&gt; remains available as a compatibility shim.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot0.png&quot; alt=&quot;moltbot0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot26.png&quot; alt=&quot;moltbot26&quot; /&gt;&lt;/p&gt;

&lt;p&gt;具体安装过程如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot3.png&quot; alt=&quot;moltbot3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot4.png&quot; alt=&quot;moltbot4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot5.png&quot; alt=&quot;moltbot5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot6.png&quot; alt=&quot;moltbot6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot7.png&quot; alt=&quot;moltbot7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot8.png&quot; alt=&quot;moltbot8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot9.png&quot; alt=&quot;moltbot9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot10.png&quot; alt=&quot;moltbot10&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot11.png&quot; alt=&quot;moltbot11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot12.png&quot; alt=&quot;moltbot12&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot13.png&quot; alt=&quot;moltbot13&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot14.png&quot; alt=&quot;moltbot14&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot15.png&quot; alt=&quot;moltbot15&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot16.png&quot; alt=&quot;moltbot16&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot17.png&quot; alt=&quot;moltbot17&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot18.png&quot; alt=&quot;moltbot18&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;uninstall&quot;&gt;&lt;a href=&quot;https://docs.molt.bot/install/uninstall&quot;&gt;Uninstall&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Uninstall the gateway service + local data (CLI remains).&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moltbot uninstall
moltbot uninstall &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--yes&lt;/span&gt;
moltbot uninstall &lt;span class=&quot;nt&quot;&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;run-the-onboarding-wizard-and-install-the-service&quot;&gt;Run the onboarding wizard (and install the service)&lt;/h1&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moltbot onboard &lt;span class=&quot;nt&quot;&gt;--install-daemon&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What you’ll choose:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Local vs Remote&lt;/strong&gt; gateway&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Auth&lt;/strong&gt;: OpenAI Code (Codex) subscription (OAuth) or API keys. For Anthropic we recommend an API key; &lt;code class=&quot;highlighter-rouge&quot;&gt;claude setup-token&lt;/code&gt; is also supported.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Providers&lt;/strong&gt;: WhatsApp QR login, Telegram/Discord bot tokens, Mattermost plugin tokens, etc.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Daemon&lt;/strong&gt;: background install (&lt;code class=&quot;highlighter-rouge&quot;&gt;launchd/systemd&lt;/code&gt;; WSL2 uses systemd)
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Runtime&lt;/strong&gt;: Node (recommended; required for WhatsApp/Telegram). Bun is not recommended.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gateway token&lt;/strong&gt;: the wizard generates one by default (even on loopback) and stores it in &lt;code class=&quot;highlighter-rouge&quot;&gt;gateway.auth.token&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wizard doc: &lt;a href=&quot;https://docs.molt.bot/start/wizard&quot;&gt;Wizard&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;auth-where-it-lives-important&quot;&gt;Auth: where it lives (important)&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Recommended Anthropic path&lt;/strong&gt;: set an API key (wizard can store it for service use). &lt;code class=&quot;highlighter-rouge&quot;&gt;claude setup-token&lt;/code&gt; is also supported if you want to reuse Claude Code credentials.&lt;/li&gt;
  &lt;li&gt;Auth profiles (OAuth + API keys): &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.clawdbot/agents/&amp;lt;agentId&amp;gt;/agent/auth-profiles.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Headless/server tip: do OAuth on a normal machine first, then copy &lt;code class=&quot;highlighter-rouge&quot;&gt;oauth.json&lt;/code&gt; to the gateway host.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot30.png&quot; alt=&quot;moltbot30&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;start-the-gateway&quot;&gt;Start the Gateway&lt;/h1&gt;

&lt;p&gt;If you installed the service during onboarding, the Gateway should already be running:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moltbot gateway status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot31.png&quot; alt=&quot;moltbot31&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Manual run (foreground):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moltbot gateway &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 18789 &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dashboard (local loopback): &lt;code class=&quot;highlighter-rouge&quot;&gt;http://127.0.0.1:18789/&lt;/code&gt; If a token is configured, paste it into the Control UI settings (stored as &lt;code class=&quot;highlighter-rouge&quot;&gt;connect.params.auth.token&lt;/code&gt;).&lt;/p&gt;

&lt;h1 id=&quot;quick-verify-2-min&quot;&gt;Quick verify (2 min)&lt;/h1&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moltbot status
moltbot status &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;

moltbot health

moltbot security audit &lt;span class=&quot;nt&quot;&gt;--deep&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tip: &lt;code class=&quot;highlighter-rouge&quot;&gt;moltbot status --all&lt;/code&gt; is the best pasteable, read-only debug report. Health probes: &lt;code class=&quot;highlighter-rouge&quot;&gt;moltbot health&lt;/code&gt; (or &lt;code class=&quot;highlighter-rouge&quot;&gt;moltbot status --deep&lt;/code&gt;) asks the running gateway for a health snapshot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot32.png&quot; alt=&quot;moltbot32&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot33.png&quot; alt=&quot;moltbot33&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot34.png&quot; alt=&quot;moltbot34&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;channles&quot;&gt;Channles&lt;/h1&gt;

&lt;h2 id=&quot;imessage&quot;&gt;&lt;a href=&quot;https://docs.molt.bot/channels/imessage&quot;&gt;Imessage&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Status: external CLI integration. Gateway spawns imsg rpc (JSON-RPC over stdio).&lt;/p&gt;

&lt;h3 id=&quot;quick-setup-beginner&quot;&gt;Quick setup (beginner)&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;Ensure Messages is signed in on this Mac.&lt;/li&gt;
  &lt;li&gt;Install &lt;code class=&quot;highlighter-rouge&quot;&gt;imsg&lt;/code&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;brew install steipete/tap/imsg&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Configure Moltbot with &lt;code class=&quot;highlighter-rouge&quot;&gt;channels.imessage.cliPath&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;channels.imessage.dbPath&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Start the gateway and approve any macOS prompts (Automation + Full Disk Access).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Minimal config:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;channels:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;imessage:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;enabled:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;cliPath:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/imsg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dbPath:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Users/&amp;lt;you&amp;gt;/Library/Messages/chat.db&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/moltbot29.png&quot; alt=&quot;moltbot29&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;使用-lighthouse-部署-openclaw-全能助手&quot;&gt;使用 lighthouse 部署 OpenClaw 全能助手&lt;/h1&gt;

&lt;h2 id=&quot;购买-openclaw-云服务&quot;&gt;购买 OpenClaw 云服务&lt;/h2&gt;

&lt;p&gt;在 https://cloud.tencent.com/act/pro/lighthouse-moltbot 上购买已经集成 OpenClaw 的服务。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw5.png&quot; alt=&quot;openclaw5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw6.png&quot; alt=&quot;openclaw6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw7.png&quot; alt=&quot;openclaw7&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;配置-openclaw&quot;&gt;配置 OpenClaw&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw8.png&quot; alt=&quot;openclaw8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw9.png&quot; alt=&quot;openclaw9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw10.png&quot; alt=&quot;openclaw10&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;qq开放平台申请机器人&quot;&gt;QQ开放平台申请机器人&lt;/h2&gt;

&lt;p&gt;在 https://q.qq.com/#/ 完成实名注册认证，然后使用注册邮箱登陆。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw11.png&quot; alt=&quot;openclaw11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw12.png&quot; alt=&quot;openclaw12&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw13.png&quot; alt=&quot;openclaw13&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw14.png&quot; alt=&quot;openclaw14&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在管理页面获取到当前机器人的 AppID 和 AppSecret，并且把自己的服务器 IP 填入到白名单中。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw15.png&quot; alt=&quot;openclaw15&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw16.png&quot; alt=&quot;openclaw16&quot; /&gt;&lt;/p&gt;

&lt;p&gt;登陆终端测试 chatbot 功能是否正常。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw17.png&quot; alt=&quot;openclaw17&quot; /&gt;&lt;/p&gt;

&lt;p&gt;添加 QQ 群和自己的 QQ 号，以调用机器人。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw18.png&quot; alt=&quot;openclaw18&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在手机端 QQ 中，添加机器人：设置 → 群机器人 → 其他&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw19.png&quot; alt=&quot;openclaw19&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw20.png&quot; alt=&quot;openclaw20&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;web-search-能力&quot;&gt;Web Search 能力&lt;/h2&gt;

&lt;h3 id=&quot;配置-brave-api-收费&quot;&gt;配置 Brave API (收费)&lt;/h3&gt;

&lt;p&gt;Brave Search 是内置的 web_search 工具，但是收费，可以让 OpenClaw 禁用它，并替换为其他免费的方案。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw21.png&quot; alt=&quot;openclaw21&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw22.png&quot; alt=&quot;openclaw22&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;配置-finnhub-免费&quot;&gt;配置 finnhub (免费)&lt;/h3&gt;

&lt;p&gt;通过 &lt;a href=&quot;https://finnhub.io/dashboard&quot;&gt;finnhub&lt;/a&gt; 查询股票价格：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw23.png&quot; alt=&quot;openclaw23&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw24.png&quot; alt=&quot;openclaw24&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;配置-tavily-免费&quot;&gt;配置 tavily (免费)&lt;/h3&gt;

&lt;p&gt;https://www.tavily.com/&lt;/p&gt;

&lt;h2 id=&quot;更多用法&quot;&gt;更多用法&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://cloud.tencent.com/developer/article/2624973&quot;&gt;云上 OpenClaw 最全实践教程合辑&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;常用命令&quot;&gt;常用命令&lt;/h1&gt;

&lt;p&gt;参考：https://zhuanlan.zhihu.com/p/2011017776756701009&lt;/p&gt;

&lt;h2 id=&quot;打开终端&quot;&gt;打开终端&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openclaw tui
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw28.png&quot; alt=&quot;openclaw28&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;查看帮助&quot;&gt;查看帮助&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看所有命令&lt;/span&gt;
openclaw &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 查看版本号&lt;/span&gt;
openclaw &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 查看特定命令的帮助&lt;/span&gt;
openclaw &amp;lt;&lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 示例：查看 config 命令帮助&lt;/span&gt;
openclaw config &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;初始化配置&quot;&gt;初始化配置&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 首次安装后初始化配置&lt;/span&gt;
openclaw setup

&lt;span class=&quot;c&quot;&gt;# 交互式引导配置（推荐新手）&lt;/span&gt;
openclaw onboard

&lt;span class=&quot;c&quot;&gt;# 打开控制面板&lt;/span&gt;
openclaw dashboard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;配置向导&quot;&gt;配置向导&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 打开完整配置向导&lt;/span&gt;
openclaw configure

&lt;span class=&quot;c&quot;&gt;# 打开特定部分配置向导&lt;/span&gt;
openclaw configure &lt;span class=&quot;nt&quot;&gt;--section&lt;/span&gt; models
openclaw configure &lt;span class=&quot;nt&quot;&gt;--section&lt;/span&gt; providers
openclaw configure &lt;span class=&quot;nt&quot;&gt;--section&lt;/span&gt; channels
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw26.png&quot; alt=&quot;openclaw26&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;查看配置&quot;&gt;查看配置&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看完整配置&lt;/span&gt;
openclaw config get

&lt;span class=&quot;c&quot;&gt;# 查看特定配置项&lt;/span&gt;
openclaw config get models.default
openclaw config get providers.mistral.apiKey

&lt;span class=&quot;c&quot;&gt;# 查看特定部分配置&lt;/span&gt;
openclaw config get &lt;span class=&quot;nt&quot;&gt;--section&lt;/span&gt; models
openclaw config get &lt;span class=&quot;nt&quot;&gt;--section&lt;/span&gt; providers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;设置配置&quot;&gt;设置配置&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 设置默认模型&lt;/span&gt;
openclaw config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;models.default mistral:mixtral-8x7b

&lt;span class=&quot;c&quot;&gt;# 设置快速模型&lt;/span&gt;
openclaw config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;models.fast mistral:mistral-7b

&lt;span class=&quot;c&quot;&gt;# 配置 Mistral API Key&lt;/span&gt;
openclaw config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;providers.mistral.apiKey YOUR_API_KEY_HERE

&lt;span class=&quot;c&quot;&gt;# 启用缓存&lt;/span&gt;
openclaw config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;cache.enabled &lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;openclaw config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;cache.maxSize 5000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;启动停止-gateway&quot;&gt;启动/停止 Gateway&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 启动 Gateway（默认端口 18789）&lt;/span&gt;
openclaw gateway start

&lt;span class=&quot;c&quot;&gt;# 自定义端口启动&lt;/span&gt;
openclaw gateway start &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 19000

&lt;span class=&quot;c&quot;&gt;# 强制启动（杀死占用进程）&lt;/span&gt;
openclaw gateway start &lt;span class=&quot;nt&quot;&gt;--force&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 停止 Gateway&lt;/span&gt;
openclaw gateway stop

&lt;span class=&quot;c&quot;&gt;# 重启 Gateway&lt;/span&gt;
openclaw gateway restart

&lt;span class=&quot;c&quot;&gt;# 查看运行状态&lt;/span&gt;
openclaw gateway status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw27.png&quot; alt=&quot;openclaw27&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;运行时-gateway&quot;&gt;运行时 Gateway&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看健康状态&lt;/span&gt;
openclaw health
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看日志&quot;&gt;查看日志&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看实时日志&lt;/span&gt;
openclaw logs

&lt;span class=&quot;c&quot;&gt;# 持续监控日志&lt;/span&gt;
openclaw logs &lt;span class=&quot;nt&quot;&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw32.png&quot; alt=&quot;openclaw32&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw33.png&quot; alt=&quot;openclaw33&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;创建新的会话-清空-token-上下文&quot;&gt;创建新的会话 (清空 token 上下文)&lt;/h2&gt;

&lt;p&gt;通过 &lt;code class=&quot;highlighter-rouge&quot;&gt;/new&lt;/code&gt; 指令来新开一个会话&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw45.png&quot; alt=&quot;openclaw45&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;系统服务管理&quot;&gt;系统服务管理&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 使用 systemd 管理（推荐生产环境）&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl start openclaw-gateway
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl stop openclaw-gateway
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart openclaw-gateway
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl status openclaw-gateway

&lt;span class=&quot;c&quot;&gt;# 开机自启动&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;openclaw-gateway
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;发送消息&quot;&gt;发送消息&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 发送消息到当前会话&lt;/span&gt;
openclaw message send &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 发送到特定目标（Telegram）&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; @mychat &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello from OpenClaw&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 发送到特定目标（WhatsApp）&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; whatsapp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; +8613800138000 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;您好&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 发送到 Slack 频道&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; slack &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; C1234567890 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;@channel 重要通知&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;发送媒体文件&quot;&gt;发送媒体文件&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 发送图片&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; @mychat &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--media&lt;/span&gt; /tmp/photo.jpg &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--caption&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;这是一张图片&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 发送音频&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; whatsapp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; +8613800138000 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--media&lt;/span&gt; /tmp/voice.mp3

&lt;span class=&quot;c&quot;&gt;# 发送文档&lt;/span&gt;
openclaw message send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; @mychat &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--media&lt;/span&gt; /tmp/report.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看技能列表&quot;&gt;查看技能列表&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看所有已安装技能&lt;/span&gt;
openclaw skills list

&lt;span class=&quot;c&quot;&gt;# 搜索技能&lt;/span&gt;
openclaw skills search weather

&lt;span class=&quot;c&quot;&gt;# 查看技能详情&lt;/span&gt;
openclaw skills show weather
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;安装卸载技能&quot;&gt;安装/卸载技能&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 安装技能&lt;/span&gt;
openclaw skills &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;weather

&lt;span class=&quot;c&quot;&gt;# 从指定来源安装&lt;/span&gt;
openclaw skills &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;weather &lt;span class=&quot;nt&quot;&gt;--source&lt;/span&gt; github

&lt;span class=&quot;c&quot;&gt;# 指定版本安装&lt;/span&gt;
openclaw skills &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;weather@1.2.0

&lt;span class=&quot;c&quot;&gt;# 卸载技能&lt;/span&gt;
openclaw skills uninstall weather
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;更新技能&quot;&gt;更新技能&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 更新所有技能&lt;/span&gt;
openclaw skills update

&lt;span class=&quot;c&quot;&gt;# 更新特定技能&lt;/span&gt;
openclaw skills update weather

&lt;span class=&quot;c&quot;&gt;# 同步技能&lt;/span&gt;
openclaw skills &lt;span class=&quot;nb&quot;&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;技能开发&quot;&gt;技能开发&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 创建新技能&lt;/span&gt;
openclaw skills create my-skill

&lt;span class=&quot;c&quot;&gt;# 验证技能&lt;/span&gt;
openclaw skills validate my-skill

&lt;span class=&quot;c&quot;&gt;# 打包技能&lt;/span&gt;
openclaw skills pack my-skill
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看频道&quot;&gt;查看频道&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看所有配置的频道&lt;/span&gt;
openclaw channels list

&lt;span class=&quot;c&quot;&gt;# 查看频道状态&lt;/span&gt;
openclaw channels status

&lt;span class=&quot;c&quot;&gt;# 查看特定频道详情&lt;/span&gt;
openclaw channels show telegram
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;登录频道&quot;&gt;登录频道&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Telegram 登录&lt;/span&gt;
openclaw channels login &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram

&lt;span class=&quot;c&quot;&gt;# WhatsApp 登录（会显示 QR 码）&lt;/span&gt;
openclaw channels login &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; whatsapp &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Slack 登录&lt;/span&gt;
openclaw channels login &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; slack

&lt;span class=&quot;c&quot;&gt;# Discord 登录&lt;/span&gt;
openclaw channels login &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; discord
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;频道测试&quot;&gt;频道测试&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 测试频道连接&lt;/span&gt;
openclaw channels &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram

&lt;span class=&quot;c&quot;&gt;# 发送测试消息&lt;/span&gt;
openclaw channels &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; @mychat &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;测试消息&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;频道配置&quot;&gt;频道配置&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 配置频道&lt;/span&gt;
openclaw channels configure &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram

&lt;span class=&quot;c&quot;&gt;# 更新频道 Token&lt;/span&gt;
openclaw channels update &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt; NEW_TOKEN

&lt;span class=&quot;c&quot;&gt;# 启用/禁用频道&lt;/span&gt;
openclaw channels &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;telegram
openclaw channels disable telegram
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看会话&quot;&gt;查看会话&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 列出所有会话&lt;/span&gt;
openclaw sessions

&lt;span class=&quot;c&quot;&gt;# 列出活跃会话&lt;/span&gt;
openclaw sessions &lt;span class=&quot;nt&quot;&gt;--active&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 列出特定频道的会话&lt;/span&gt;
openclaw sessions &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; telegram

&lt;span class=&quot;c&quot;&gt;# 显示最近 10 个会话&lt;/span&gt;
openclaw sessions &lt;span class=&quot;nt&quot;&gt;--limit&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;会话操作&quot;&gt;会话操作&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 发送消息到会话&lt;/span&gt;
openclaw sessions send &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--session&lt;/span&gt; &amp;lt;session-key&amp;gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;你好&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 重置会话&lt;/span&gt;
openclaw sessions reset &amp;lt;session-key&amp;gt;

&lt;span class=&quot;c&quot;&gt;# 删除会话&lt;/span&gt;
openclaw sessions delete &amp;lt;session-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看节点&quot;&gt;查看节点&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看所有配对的节点&lt;/span&gt;
openclaw nodes list

&lt;span class=&quot;c&quot;&gt;# 查看节点状态&lt;/span&gt;
openclaw nodes status

&lt;span class=&quot;c&quot;&gt;# 描述节点详情&lt;/span&gt;
openclaw nodes describe &amp;lt;node-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;节点操作&quot;&gt;节点操作&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 发送通知到节点&lt;/span&gt;
openclaw nodes notify &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; my-phone &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--title&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;提醒&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--body&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;该吃饭了&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 设置推送优先级&lt;/span&gt;
openclaw nodes notify &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; my-phone &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--priority&lt;/span&gt; timeSensitive &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--title&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;紧急通知&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--body&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;快递到了&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 查看相册（手机）&lt;/span&gt;
openclaw nodes camera-list &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; my-phone

&lt;span class=&quot;c&quot;&gt;# 拍照&lt;/span&gt;
openclaw nodes camera-snap &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--node&lt;/span&gt; my-phone &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--facing&lt;/span&gt; back &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; /tmp/photo.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;搜索记忆&quot;&gt;搜索记忆&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 搜索记忆&lt;/span&gt;
openclaw memory search &lt;span class=&quot;s2&quot;&gt;&quot;OpenClaw 配置&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 搜索并显示多行上下文&lt;/span&gt;
openclaw memory search &lt;span class=&quot;s2&quot;&gt;&quot;配置&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--lines&lt;/span&gt; 5

&lt;span class=&quot;c&quot;&gt;# 搜索特定路径的记忆&lt;/span&gt;
openclaw memory search &lt;span class=&quot;s2&quot;&gt;&quot;配置&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--path&lt;/span&gt; MEMORY.md

&lt;span class=&quot;c&quot;&gt;# 限制结果数量&lt;/span&gt;
openclaw memory search &lt;span class=&quot;s2&quot;&gt;&quot;配置&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--maxResults&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;记忆操作&quot;&gt;记忆操作&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看记忆统计&lt;/span&gt;
openclaw memory stats

&lt;span class=&quot;c&quot;&gt;# 清理过期记忆&lt;/span&gt;
openclaw memory clean

&lt;span class=&quot;c&quot;&gt;# 备份记忆&lt;/span&gt;
openclaw memory backup &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; /tmp/memory-backup.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;查看-cron-任务&quot;&gt;查看 Cron 任务&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 列出所有任务&lt;/span&gt;
openclaw cron list

&lt;span class=&quot;c&quot;&gt;# 查看任务运行历史&lt;/span&gt;
openclaw cron runs &amp;lt;job-id&amp;gt;

&lt;span class=&quot;c&quot;&gt;# 查看调度器状态&lt;/span&gt;
openclaw cron status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;创建-cron-任务&quot;&gt;创建 Cron 任务&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 创建定时任务（每天凌晨触发）&lt;/span&gt;
openclaw cron add &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;daily-report&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--schedule&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0 0 * * *&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;生成每日报告&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 创建重复任务（每 30 分钟）&lt;/span&gt;
openclaw cron add &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;check-notifications&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--schedule&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*/30 * * * *&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;检查通知&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 创建单次任务（特定时间）&lt;/span&gt;
openclaw cron add &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;special-task&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--schedule&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;at&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--at&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2026-03-01T10:00:00&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;执行特殊任务&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cron-任务操作&quot;&gt;Cron 任务操作&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 立即运行任务&lt;/span&gt;
openclaw cron run &amp;lt;job-id&amp;gt;

&lt;span class=&quot;c&quot;&gt;# 更新任务&lt;/span&gt;
openclaw cron update &amp;lt;job-id&amp;gt; &lt;span class=&quot;nt&quot;&gt;--schedule&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0 6 * * *&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 删除任务&lt;/span&gt;
openclaw cron remove &amp;lt;job-id&amp;gt;

&lt;span class=&quot;c&quot;&gt;# 发送唤醒事件&lt;/span&gt;
openclaw cron wake &lt;span class=&quot;nt&quot;&gt;--text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;检查新消息&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;健康检查&quot;&gt;健康检查&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 运行健康检查&lt;/span&gt;
openclaw doctor

&lt;span class=&quot;c&quot;&gt;# 快速修复常见问题&lt;/span&gt;
openclaw doctor &lt;span class=&quot;nt&quot;&gt;--fix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;系统状态&quot;&gt;系统状态&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看频道健康状态&lt;/span&gt;
openclaw status

&lt;span class=&quot;c&quot;&gt;# 查看系统事件&lt;/span&gt;
openclaw system events

&lt;span class=&quot;c&quot;&gt;# 查看心跳状态&lt;/span&gt;
openclaw system heartbeat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;安全检查&quot;&gt;安全检查&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 运行安全检查&lt;/span&gt;
openclaw security audit

&lt;span class=&quot;c&quot;&gt;# 检查权限配置&lt;/span&gt;
openclaw security check-permissions

&lt;span class=&quot;c&quot;&gt;# 检查 API Key 有效性&lt;/span&gt;
openclaw security verify-keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;更新-openclaw&quot;&gt;更新 OpenClaw&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看更新&lt;/span&gt;
openclaw update &lt;span class=&quot;nt&quot;&gt;--dry-run&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 执行更新&lt;/span&gt;
openclaw update

&lt;span class=&quot;c&quot;&gt;# 更新到特定版本&lt;/span&gt;
openclaw update &lt;span class=&quot;nt&quot;&gt;--tag&lt;/span&gt; 2026.2.22

&lt;span class=&quot;c&quot;&gt;# 更新到 Beta 版&lt;/span&gt;
openclaw update &lt;span class=&quot;nt&quot;&gt;--channel&lt;/span&gt; beta

&lt;span class=&quot;c&quot;&gt;# 安全更新流程&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; ~/.openclaw/config.json ~/.openclaw/config.json.backup &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; openclaw update &lt;span class=&quot;nt&quot;&gt;--dry-run&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; openclaw update &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;qa&quot;&gt;Q&amp;amp;A&lt;/h1&gt;

&lt;h2 id=&quot;minimax-接口配置&quot;&gt;MiniMax 接口配置&lt;/h2&gt;

&lt;p&gt;由于 Kimi、MiniMax、GLM 分了国际版和国内版，Clawdbot 默认集成的是&lt;strong&gt;国际版的接口地址&lt;/strong&gt;，因此如果在配置模型时需要使用这三家的模型，则需要登录国际版控制台申请 API Key：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Kimi：https://platform.moonshot.ai/&lt;/li&gt;
  &lt;li&gt;MiniMax：https://platform.minimax.io/&lt;/li&gt;
  &lt;li&gt;GLM：https://z.ai/manage-apikey/apikey-list&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;升级-openclaw-版本之后用户之前安装的-skill-失效了&quot;&gt;升级 openclaw 版本之后用户之前安装的 skill 失效了&lt;/h2&gt;

&lt;p&gt;问题现象：openclaw 升级到 2026.3.2 版本后，出现 openclaw 访问权限错误，工作区下 Skills (&lt;code class=&quot;highlighter-rouge&quot;&gt;/root/.openclaw/workspace/skills/&lt;/code&gt;) 都会提示工具不可用。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# openclaw --version&lt;/span&gt;
2026.3.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;问题原因：openclaw 的版本权限收拢了，之前没有这个限制。查看 &lt;code class=&quot;highlighter-rouge&quot;&gt;cat /root/.openclaw/openclaw.json | grep profile&lt;/code&gt;，新版本默认为 &lt;code class=&quot;highlighter-rouge&quot;&gt;messaging&lt;/code&gt;，需要将其改为 &lt;code class=&quot;highlighter-rouge&quot;&gt;full&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;gateway-异常修复&quot;&gt;gateway 异常修复&lt;/h2&gt;

&lt;p&gt;问题现象：使用 openclaw onboard 重新安装 gateway 出现异常导致 gateway 被删除且安装失败。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw49.png&quot; alt=&quot;openclaw49&quot; /&gt;&lt;/p&gt;

&lt;p&gt;使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw gateway install --force&lt;/code&gt; 重新安装也会提示失败。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/openclaw48.png&quot; alt=&quot;openclaw48&quot; /&gt;&lt;/p&gt;

&lt;p&gt;参考：https://www.answeroverflow.com/m/1478602967488790682?focus=1478602967488790682 找到了解决方法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;systemctl --user is-enabled openclaw-gateway.service&lt;/code&gt; → &lt;strong&gt;not-found&lt;/strong&gt; means the systemd user unit was never installed&lt;/li&gt;
  &lt;li&gt;Let Doctor rewrite the service to a sane modern config (incl. PATH): &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw doctor --repair&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Restart: &lt;code class=&quot;highlighter-rouge&quot;&gt;openclaw gateway restart&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Verify: &lt;code class=&quot;highlighter-rouge&quot;&gt;systemctl --user status openclaw-gateway.service --no-pager &amp;amp;&amp;amp; openclaw gateway status&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Log: &lt;code class=&quot;highlighter-rouge&quot;&gt;journalctl --user -u openclaw-gateway.service -n 200 --no-pager&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;link-channel-unknown-错误&quot;&gt;Link channel: unknown 错误&lt;/h2&gt;

&lt;p&gt;问题现象：使用 tui channel 没有实时返回结果信息，而显示 &lt;code class=&quot;highlighter-rouge&quot;&gt;gateway connected | idle&lt;/code&gt; 状态。&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;https://www.molt.bot/&lt;/li&gt;
  &lt;li&gt;https://docs.molt.bot/&lt;/li&gt;
  &lt;li&gt;https://github.com/moltbot/moltbot&lt;/li&gt;
  &lt;li&gt;https://docs.molt.bot/getting-started&lt;/li&gt;
  &lt;li&gt;https://docs.molt.bot/start/getting-started&lt;/li&gt;
  &lt;li&gt;https://docs.molt.bot/help/troubleshooting&lt;/li&gt;
  &lt;li&gt;https://docs.molt.bot/help/faq&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.infoq.cn/news/Nb7WV3WYhhCoGdlq6MZy&quot;&gt;被 Anthropic 强制要求改名！Clawdbot 创始人一人开发、100% AI 写代码&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cloud.tencent.com/developer/article/2624973&quot;&gt;云上Moltbot（原Clawdbot）最全实践指南合辑&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cloud.tencent.com/developer/article/2625147&quot;&gt;云上Moltbot（原Clawdbot）接入企业微信完全指南&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cloud.tencent.com/developer/article/2625097&quot;&gt;云上Moltbot（原Clawdbot）接入QQ完全指南&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="ML" /><summary type="html"></summary></entry><entry><title type="html">School English Notes</title><link href="http://172.19.0.16:8080/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0/2026/01/17/school-english-words.html" rel="alternate" type="text/html" title="School English Notes" /><published>2026-01-17T12:30:00+08:00</published><updated>2026-01-17T12:30:00+08:00</updated><id>http://172.19.0.16:8080/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0/2026/01/17/school-english-words</id><content type="html" xml:base="http://172.19.0.16:8080/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0/2026/01/17/school-english-words.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#单词记忆方法&quot; id=&quot;markdown-toc-单词记忆方法&quot;&gt;单词记忆方法&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#1-分类记忆法按主题分组&quot; id=&quot;markdown-toc-1-分类记忆法按主题分组&quot;&gt;1. 分类记忆法（按主题分组）&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#2-艾宾浩斯遗忘曲线复习法&quot; id=&quot;markdown-toc-2-艾宾浩斯遗忘曲线复习法&quot;&gt;2. 艾宾浩斯遗忘曲线复习法&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#3-联想记忆法&quot; id=&quot;markdown-toc-3-联想记忆法&quot;&gt;3. 联想记忆法&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#4-卡片记忆法&quot; id=&quot;markdown-toc-4-卡片记忆法&quot;&gt;4. 卡片记忆法&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#5-口诀记忆法&quot; id=&quot;markdown-toc-5-口诀记忆法&quot;&gt;5. 口诀记忆法&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#6-重点攻克难点单词&quot; id=&quot;markdown-toc-6-重点攻克难点单词&quot;&gt;6. 重点攻克难点单词&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#7-实战练习建议&quot; id=&quot;markdown-toc-7-实战练习建议&quot;&gt;7. 实战练习建议&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#8-考前冲刺最后1-2天&quot; id=&quot;markdown-toc-8-考前冲刺最后1-2天&quot;&gt;8. 考前冲刺（最后1-2天）&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#英语五年级上册单词&quot; id=&quot;markdown-toc-英语五年级上册单词&quot;&gt;英语五年级上册单词&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-1&quot; id=&quot;markdown-toc-unit-1&quot;&gt;Unit 1&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-2&quot; id=&quot;markdown-toc-unit-2&quot;&gt;Unit 2&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-3&quot; id=&quot;markdown-toc-unit-3&quot;&gt;Unit 3&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-4&quot; id=&quot;markdown-toc-unit-4&quot;&gt;Unit 4&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-5&quot; id=&quot;markdown-toc-unit-5&quot;&gt;Unit 5&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-6&quot; id=&quot;markdown-toc-unit-6&quot;&gt;Unit 6&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-7&quot; id=&quot;markdown-toc-unit-7&quot;&gt;Unit 7&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-8&quot; id=&quot;markdown-toc-unit-8&quot;&gt;Unit 8&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-9&quot; id=&quot;markdown-toc-unit-9&quot;&gt;Unit 9&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-10&quot; id=&quot;markdown-toc-unit-10&quot;&gt;Unit 10&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-11&quot; id=&quot;markdown-toc-unit-11&quot;&gt;Unit 11&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-12&quot; id=&quot;markdown-toc-unit-12&quot;&gt;Unit 12&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#英语六年级上册单词&quot; id=&quot;markdown-toc-英语六年级上册单词&quot;&gt;英语六年级上册单词&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#unit-1-1&quot; id=&quot;markdown-toc-unit-1-1&quot;&gt;Unit 1&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;教材：上海教育出版社&lt;/p&gt;

&lt;h1 id=&quot;单词记忆方法&quot;&gt;单词记忆方法&lt;/h1&gt;

&lt;h2 id=&quot;1-分类记忆法按主题分组&quot;&gt;1. 分类记忆法（按主题分组）&lt;/h2&gt;
&lt;p&gt;将单词按主题分类，同类单词一起记忆效果更好：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unit 1&lt;/strong&gt;: 职业类（pilot, cook, singer, lifeguard）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 2&lt;/strong&gt;: 交通类（by bus, by bike, station, underground）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 3&lt;/strong&gt;: 序数词（first, second, third…）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 4&lt;/strong&gt;: 频率副词（usually, often, sometimes, always, never）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 5&lt;/strong&gt;: 日常交流类（clever, same, class, ask, answer, each other）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 6&lt;/strong&gt;: 房间类（living room, bedroom, kitchen, bathroom）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 7&lt;/strong&gt;: 度假类（beach, sunshine, shell, sea）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 8&lt;/strong&gt;: 远足探险类（outing, map, hill, find, diamond, lake）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 9&lt;/strong&gt;: 方向类（left, right, straight, turn）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 10&lt;/strong&gt;: 副词类（gently, softly, strongly, slowly, quickly）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 11&lt;/strong&gt;: 生活自然类（tap, use, vegetable, farmer, mountain, tree）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Unit 12&lt;/strong&gt;: 安全类（fire, burn, safety, careful）&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-艾宾浩斯遗忘曲线复习法&quot;&gt;2. 艾宾浩斯遗忘曲线复习法&lt;/h2&gt;
&lt;p&gt;根据遗忘曲线规律，科学安排复习时间：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;第1天&lt;/strong&gt;：学习 Unit 1-4&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第2天&lt;/strong&gt;：复习 Unit 1-4，学习 Unit 5-8&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第3天&lt;/strong&gt;：复习 Unit 1-8，学习 Unit 9-12&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;第4天&lt;/strong&gt;：全面复习，重点攻克薄弱单元&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-联想记忆法&quot;&gt;3. 联想记忆法&lt;/h2&gt;
&lt;p&gt;通过联想帮助记忆：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;词根联想&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;underground&lt;/code&gt; = under（下）+ ground（地面）= 地铁&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;音形联想&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;journey&lt;/code&gt; 听起来像”就你”，想象”旅程就你一个人”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;场景联想&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;living room&lt;/code&gt;（客厅）→ 生活的地方&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-卡片记忆法&quot;&gt;4. 卡片记忆法&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;制作单词卡片：正面英文，背面中文&lt;/li&gt;
  &lt;li&gt;快速过一遍，把会的放一边，不会的反复看&lt;/li&gt;
  &lt;li&gt;利用碎片时间（上学路上、课间）复习&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;5-口诀记忆法&quot;&gt;5. 口诀记忆法&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;序数词规律&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;first, second, third&lt;/code&gt; 特殊记，&lt;code class=&quot;highlighter-rouge&quot;&gt;fourth&lt;/code&gt; 开始加 &lt;code class=&quot;highlighter-rouge&quot;&gt;-th&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;频率副词排序&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;always &amp;gt; usually &amp;gt; often &amp;gt; sometimes &amp;gt; never&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;6-重点攻克难点单词&quot;&gt;6. 重点攻克难点单词&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;长单词&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;favourite&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;interesting&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;thirteenth&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;twenty-first&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;易混淆&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;bring&lt;/code&gt; vs &lt;code class=&quot;highlighter-rouge&quot;&gt;thing&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;quiet&lt;/code&gt; (/ˈkwaɪət/) vs &lt;code class=&quot;highlighter-rouge&quot;&gt;quite&lt;/code&gt; (/kwaɪt/)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;短语&lt;/strong&gt;：&lt;code class=&quot;highlighter-rouge&quot;&gt;(be) good at&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;have a good time&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;each other&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;7-实战练习建议&quot;&gt;7. 实战练习建议&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;每天默写1-2个单元&lt;/li&gt;
  &lt;li&gt;用单词造句，加深理解&lt;/li&gt;
  &lt;li&gt;找同学互相听写，互相纠正&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;8-考前冲刺最后1-2天&quot;&gt;8. 考前冲刺（最后1-2天）&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;快速浏览所有单词，标记不熟悉的&lt;/li&gt;
  &lt;li&gt;重点复习标记的单词&lt;/li&gt;
  &lt;li&gt;做模拟测试，查漏补缺&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;英语五年级上册单词&quot;&gt;英语五年级上册单词&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202601/5_shang_en_words.png&quot; alt=&quot;5_shang_en_words&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;unit-1&quot;&gt;Unit 1&lt;/h2&gt;

&lt;p&gt;Title: My future Category: 职业类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;future /ˈfjuːtʃə/ 将来；未来
    &lt;ul&gt;
      &lt;li&gt;例句：I want to be a teacher in the future. (我将来想成为一名老师。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;want /wɒnt/ 想要
    &lt;ul&gt;
      &lt;li&gt;例句：I want an apple. (我想要一个苹果。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;pilot /ˈpaɪlət/ 飞行员
    &lt;ul&gt;
      &lt;li&gt;例句：My uncle is a pilot. (我叔叔是一名飞行员。)&lt;/li&gt;
      &lt;li&gt;记忆：pilot 开飞机，pilot 很厉害！&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;teach /tiːtʃ/ 教(课)
    &lt;ul&gt;
      &lt;li&gt;例句：My teacher teaches English. (我的老师教英语。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;cook /kʊk/ 厨师；烹饪
    &lt;ul&gt;
      &lt;li&gt;例句：My mother is a good cook. (我妈妈是个好厨师。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;taxi driver /ˈtæksi ˈdraɪvə/ 出租车司机
    &lt;ul&gt;
      &lt;li&gt;例句：The taxi driver is very friendly. (出租车司机很友好。)&lt;/li&gt;
      &lt;li&gt;记忆：taxi（出租车）+ driver（司机）= taxi driver&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;job /dʒɒb/ 工作；职业
    &lt;ul&gt;
      &lt;li&gt;例句：What’s your job? (你的工作是什么？)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;singer /ˈsɪŋə/ 歌手
    &lt;ul&gt;
      &lt;li&gt;例句：She wants to be a singer. (她想成为一名歌手。)&lt;/li&gt;
      &lt;li&gt;记忆：sing（唱歌）+ er（人）= singer（歌手）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fall /fɔːl/ 掉落；落下
    &lt;ul&gt;
      &lt;li&gt;例句：The apple falls from the tree. (苹果从树上掉下来。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;lifeguard /ˈlaɪfɡɑːd/ 救生员
    &lt;ul&gt;
      &lt;li&gt;例句：The lifeguard helps people at the beach. (救生员在海滩帮助人们。)&lt;/li&gt;
      &lt;li&gt;记忆：life（生命）+ guard（守卫）= lifeguard（救生员）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;save /seɪv/ 救；救助；节约
    &lt;ul&gt;
      &lt;li&gt;例句：The lifeguard saves people. (救生员救人。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;become /bɪˈkʌm/ 变成；变得
    &lt;ul&gt;
      &lt;li&gt;例句：I want to become a doctor. (我想成为一名医生。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;(be) good at /biː ɡʊd æt/ 擅长
    &lt;ul&gt;
      &lt;li&gt;例句：I am good at English. (我擅长英语。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-2&quot;&gt;Unit 2&lt;/h2&gt;

&lt;p&gt;Title: Going to school Category: 交通类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;by /baɪ/ (表示方式)；靠近
    &lt;ul&gt;
      &lt;li&gt;例句：I go to school by bus. (我乘公共汽车去学校。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;walk /wɔːk/ 走；步行
    &lt;ul&gt;
      &lt;li&gt;例句：I walk to school every day. (我每天步行去学校。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Ms /mɪz/ 女士
    &lt;ul&gt;
      &lt;li&gt;例句：Ms Wang is my teacher. (王女士是我的老师。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;journey /ˈdʒɜːni/ 旅程；旅行
    &lt;ul&gt;
      &lt;li&gt;例句：It’s a long journey. (这是一次长途旅行。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;primary school /ˈpraɪməri skuːl/ 小学
    &lt;ul&gt;
      &lt;li&gt;例句：I study at a primary school. (我在小学学习。)&lt;/li&gt;
      &lt;li&gt;记忆：primary（初级的）+ school（学校）= primary school（小学）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;underground /ˈʌndəɡraʊnd/ 地铁
    &lt;ul&gt;
      &lt;li&gt;例句：I take the underground to school. (我乘地铁去学校。)&lt;/li&gt;
      &lt;li&gt;记忆：under（下）+ ground（地面）= underground（地铁）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;station /ˈsteɪʃən/ 车站
    &lt;ul&gt;
      &lt;li&gt;例句：The train station is big. (火车站很大。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;take /teɪk/ 乘坐(交通工具)；带领
    &lt;ul&gt;
      &lt;li&gt;例句：I take the bus to school. (我乘公共汽车去学校。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;after /ˈɑːftə/ 在……后
    &lt;ul&gt;
      &lt;li&gt;例句：I do homework after school. (放学后我做作业。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hour /ˈaʊə/ 小时
    &lt;ul&gt;
      &lt;li&gt;例句：I sleep for eight hours. (我睡八小时。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bus stop /bʌs stɒp/ 公共汽车站
    &lt;ul&gt;
      &lt;li&gt;例句：I wait at the bus stop. (我在公共汽车站等车。)&lt;/li&gt;
      &lt;li&gt;记忆：bus（公共汽车）+ stop（站）= bus stop&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;by bus /baɪ bʌs/ 乘公共汽车
    &lt;ul&gt;
      &lt;li&gt;例句：I go home by bus. (我乘公共汽车回家。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;far from /fɑː frɒm/ 离……远
    &lt;ul&gt;
      &lt;li&gt;例句：My school is far from my home. (我的学校离我家很远。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;on foot /ɒn fʊt/ 步行
    &lt;ul&gt;
      &lt;li&gt;例句：I go to the park on foot. (我步行去公园。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;by bike /baɪ baɪk/ 骑自行车
    &lt;ul&gt;
      &lt;li&gt;例句：I go to school by bike. (我骑自行车去学校。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;by car /baɪ kɑː/ 乘小汽车
    &lt;ul&gt;
      &lt;li&gt;例句：My father goes to work by car. (我爸爸开车去上班。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;get off /ɡet ɒf/ 下车
    &lt;ul&gt;
      &lt;li&gt;例句：I get off the bus at the school. (我在学校下车。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-3&quot;&gt;Unit 3&lt;/h2&gt;

&lt;p&gt;Title: My birthday Category: 序数词&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;party /ˈpɑːti/ 聚会
    &lt;ul&gt;
      &lt;li&gt;例句：I go to a birthday party. (我去参加生日聚会。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;when /wen/ 什么时候
    &lt;ul&gt;
      &lt;li&gt;例句：When do you go to school? (你什么时候去学校？)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;begin /bɪˈɡɪn/ 开始
    &lt;ul&gt;
      &lt;li&gt;例句：The class begins at eight. (课在八点开始。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bring /brɪŋ/ 带来
    &lt;ul&gt;
      &lt;li&gt;例句：Please bring your book. (请带上你的书。)&lt;/li&gt;
      &lt;li&gt;记忆：bring（带来）和 thing（东西）容易混淆，bring 是动作&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;thing /θɪŋ/ 东西；事物
    &lt;ul&gt;
      &lt;li&gt;例句：This is a nice thing. (这是一个好东西。)&lt;/li&gt;
      &lt;li&gt;记忆：thing（东西）和 bring（带来）容易混淆，thing 是名词&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;favourite /ˈfeɪvərɪt/ 最喜欢的
    &lt;ul&gt;
      &lt;li&gt;例句：Apple is my favourite fruit. (苹果是我最喜欢的水果。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;interesting /ˈɪntrəstɪŋ/ 有趣的
    &lt;ul&gt;
      &lt;li&gt;例句：This book is very interesting. (这本书很有趣。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hat /hæt/ 帽子
    &lt;ul&gt;
      &lt;li&gt;例句：I wear a red hat. (我戴一顶红帽子。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;have fun /hæv fʌn/ 尽情玩
    &lt;ul&gt;
      &lt;li&gt;例句：We have fun at the party. (我们在聚会上玩得很开心。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;first /fɜːst/ 第一
    &lt;ul&gt;
      &lt;li&gt;例句：I am the first in the race. (我在比赛中得了第一。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;second /ˈsekənd/ 第二
    &lt;ul&gt;
      &lt;li&gt;例句：He is the second student. (他是第二个学生。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;third /θɜːd/ 第三
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the third day. (今天是第三天。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fourth /fɔːθ/ 第四
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the fourth day. (今天是第四天。)&lt;/li&gt;
      &lt;li&gt;记忆：four（四）+ th = fourth（第四）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fifth /fɪfθ/ 第五
    &lt;ul&gt;
      &lt;li&gt;例句：This is the fifth book. (这是第五本书。)&lt;/li&gt;
      &lt;li&gt;记忆：five（五）→ fifth（第五），注意 ve 变 f 再加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sixth /sɪksθ/ 第六
    &lt;ul&gt;
      &lt;li&gt;例句：I am in the sixth grade. (我在六年级。)&lt;/li&gt;
      &lt;li&gt;记忆：six（六）+ th = sixth（第六）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;seventh /ˈsevənθ/ 第七
    &lt;ul&gt;
      &lt;li&gt;例句：This is the seventh month. (这是第七个月。)&lt;/li&gt;
      &lt;li&gt;记忆：seven（七）+ th = seventh（第七）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;eighth /eɪtθ/ 第八
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the eighth day. (今天是第八天。)&lt;/li&gt;
      &lt;li&gt;记忆：eight（八）+ th = eighth（第八），注意只有一个 t&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;ninth /naɪnθ/ 第九
    &lt;ul&gt;
      &lt;li&gt;例句：This is the ninth lesson. (这是第九课。)&lt;/li&gt;
      &lt;li&gt;记忆：nine（九）→ ninth（第九），去掉 e 加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;tenth /tenθ/ 第十
    &lt;ul&gt;
      &lt;li&gt;例句：This is the tenth question. (这是第十个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：ten（十）+ th = tenth（第十）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;eleventh /ɪˈlevənθ/ 第十一
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the eleventh day. (今天是第十一天。)&lt;/li&gt;
      &lt;li&gt;记忆：eleven（十一）+ th = eleventh（第十一）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twelfth /twelfθ/ 第十二
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twelfth month. (这是第十二个月。)&lt;/li&gt;
      &lt;li&gt;记忆：twelve（十二）→ twelfth（第十二），注意 ve 变 f 再加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;thirteenth /ˌθɜːˈtiːnθ/ 第十三
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the thirteenth day. (今天是第十三天。)&lt;/li&gt;
      &lt;li&gt;记忆：thirteen（十三）+ th = thirteenth（第十三）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fourteenth /ˌfɔːˈtiːnθ/ 第十四
    &lt;ul&gt;
      &lt;li&gt;例句：This is the fourteenth lesson. (这是第十四课。)&lt;/li&gt;
      &lt;li&gt;记忆：fourteen（十四）+ th = fourteenth（第十四）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fifteenth /ˌfɪfˈtiːnθ/ 第十五
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the fifteenth day. (今天是第十五天。)&lt;/li&gt;
      &lt;li&gt;记忆：fifteen（十五）+ th = fifteenth（第十五）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sixteenth /ˌsɪkˈstiːnθ/ 第十六
    &lt;ul&gt;
      &lt;li&gt;例句：This is the sixteenth question. (这是第十六个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：sixteen（十六）+ th = sixteenth（第十六）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;seventeenth /ˌsevənˈtiːnθ/ 第十七
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the seventeenth day. (今天是第十七天。)&lt;/li&gt;
      &lt;li&gt;记忆：seventeen（十七）+ th = seventeenth（第十七）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;eighteenth /ˌeɪˈtiːnθ/ 第十八
    &lt;ul&gt;
      &lt;li&gt;例句：This is the eighteenth lesson. (这是第十八课。)&lt;/li&gt;
      &lt;li&gt;记忆：eighteen（十八）+ th = eighteenth（第十八）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;nineteenth /ˌnaɪnˈtiːnθ/ 第十九
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the nineteenth day. (今天是第十九天。)&lt;/li&gt;
      &lt;li&gt;记忆：nineteen（十九）→ nineteenth（第十九），去掉 e 加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twentieth /ˈtwentiəθ/ 第二十
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twentieth question. (这是第二十个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）→ twentieth（第二十），y 变 ie 加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-first /ˌtwenti ˈfɜːst/ 第二十一
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the twenty-first day. (今天是第二十一天。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ first（第一）= twenty-first&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-second /ˌtwenti ˈsekənd/ 第二十二
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twenty-second lesson. (这是第二十二课。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ second（第二）= twenty-second&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-third /ˌtwenti ˈθɜːd/ 第二十三
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the twenty-third day. (今天是第二十三天。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ third（第三）= twenty-third&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-fourth /ˌtwenti ˈfɔːθ/ 第二十四
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twenty-fourth question. (这是第二十四个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ fourth（第四）= twenty-fourth&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-fifth /ˌtwenti ˈfɪfθ/ 第二十五
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the twenty-fifth day. (今天是第二十五天。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ fifth（第五）= twenty-fifth&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-sixth /ˌtwenti ˈsɪksθ/ 第二十六
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twenty-sixth lesson. (这是第二十六课。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ sixth（第六）= twenty-sixth&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-seventh /ˌtwenti ˈsevənθ/ 第二十七
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the twenty-seventh day. (今天是第二十七天。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ seventh（第七）= twenty-seventh&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-eighth /ˌtwenti ˈeɪtθ/ 第二十八
    &lt;ul&gt;
      &lt;li&gt;例句：This is the twenty-eighth question. (这是第二十八个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ eighth（第八）= twenty-eighth&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;twenty-ninth /ˌtwenti ˈnaɪnθ/ 第二十九
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the twenty-ninth day. (今天是第二十九天。)&lt;/li&gt;
      &lt;li&gt;记忆：twenty（二十）+ ninth（第九）= twenty-ninth&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;thirtieth /ˈθɜːtiəθ/ 第三十
    &lt;ul&gt;
      &lt;li&gt;例句：This is the thirtieth question. (这是第三十个问题。)&lt;/li&gt;
      &lt;li&gt;记忆：thirty（三十）→ thirtieth（第三十），y 变 ie 加 th&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;thirty-first /ˌθɜːti ˈfɜːst/ 第三十一
    &lt;ul&gt;
      &lt;li&gt;例句：Today is the thirty-first day. (今天是第三十一天。)&lt;/li&gt;
      &lt;li&gt;记忆：thirty（三十）+ first（第一）= thirty-first&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-4&quot;&gt;Unit 4&lt;/h2&gt;

&lt;p&gt;Title: Grandparents Category: 频率副词&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;usually /ˈjuːʒuəli/ 通常
    &lt;ul&gt;
      &lt;li&gt;例句：I usually go to school at seven. (我通常七点去学校。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;often /ˈɒfən/ 经常
    &lt;ul&gt;
      &lt;li&gt;例句：I often read books. (我经常读书。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;visit /ˈvɪzɪt/ 看望；拜访；参观
    &lt;ul&gt;
      &lt;li&gt;例句：I visit my grandparents. (我看望我的祖父母。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sometimes /ˈsʌmtaɪmz/ 有时
    &lt;ul&gt;
      &lt;li&gt;例句：Sometimes I play football. (有时我踢足球。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;always /ˈɔːlweɪz/ 总是；一直
    &lt;ul&gt;
      &lt;li&gt;例句：I always do my homework. (我总是做作业。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;never /ˈnevə/ 从不
    &lt;ul&gt;
      &lt;li&gt;例句：I never go to bed late. (我从不晚睡。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;play sport /pleɪ spɔːt/ 做运动
    &lt;ul&gt;
      &lt;li&gt;例句：I play sport every day. (我每天做运动。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;go shopping /ɡəʊ ˈʃɒpɪŋ/ 去购物
    &lt;ul&gt;
      &lt;li&gt;例句：My mother goes shopping on Sunday. (我妈妈星期天去购物。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-5&quot;&gt;Unit 5&lt;/h2&gt;

&lt;p&gt;Title: Friends Category: 日常交流类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;clever /ˈklevə/ 聪明的
    &lt;ul&gt;
      &lt;li&gt;例句：Tom is a clever boy. (汤姆是个聪明的男孩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;same /seɪm/ 相同的
    &lt;ul&gt;
      &lt;li&gt;例句：We are in the same class. (我们在同一个班级。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;class /klɑːs/ 班；班级
    &lt;ul&gt;
      &lt;li&gt;例句：I am in Class One. (我在一班。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;both /bəʊθ/ (两个)都
    &lt;ul&gt;
      &lt;li&gt;例句：Both of us like English. (我们两个都喜欢英语。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;cross /krɒs/ 穿越；越过
    &lt;ul&gt;
      &lt;li&gt;例句：Don’t cross the road here. (不要在这里过马路。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;carry /ˈkæri/ 背；提；拿
    &lt;ul&gt;
      &lt;li&gt;例句：I carry a heavy bag. (我背着一个重包。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;heavy /ˈhevi/ 重的；沉的
    &lt;ul&gt;
      &lt;li&gt;例句：This box is very heavy. (这个箱子很重。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;different /ˈdɪfərənt/ 不同的
    &lt;ul&gt;
      &lt;li&gt;例句：We are different. (我们是不同的。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bored /bɔːd/ 无聊的
    &lt;ul&gt;
      &lt;li&gt;例句：I feel bored. (我感到无聊。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;word /wɜːd/ 单词
    &lt;ul&gt;
      &lt;li&gt;例句：This is a new word. (这是一个新单词。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;easy /ˈiːzi/ 容易的
    &lt;ul&gt;
      &lt;li&gt;例句：This question is easy. (这个问题很容易。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;say /seɪ/ 说
    &lt;ul&gt;
      &lt;li&gt;例句：What do you say? (你说什么？)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;then /ðen/ 然后；那么
    &lt;ul&gt;
      &lt;li&gt;例句：First I read, then I write. (我先读，然后写。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;ask /ɑːsk/ 问
    &lt;ul&gt;
      &lt;li&gt;例句：I ask the teacher a question. (我问老师一个问题。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;answer /ˈɑːnsə/ 回答
    &lt;ul&gt;
      &lt;li&gt;例句：Please answer my question. (请回答我的问题。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;soon /suːn/ 很快；不久
    &lt;ul&gt;
      &lt;li&gt;例句：I will come back soon. (我很快回来。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;each other /iːtʃ ˈʌðə/ 互相
    &lt;ul&gt;
      &lt;li&gt;例句：We help each other. (我们互相帮助。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;make phone calls /meɪk fəʊn kɔːlz/ 打电话
    &lt;ul&gt;
      &lt;li&gt;例句：I make phone calls to my friends. (我给朋友打电话。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-6&quot;&gt;Unit 6&lt;/h2&gt;

&lt;p&gt;Title: Family life Category: 房间类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;life /laɪf/ 生活
    &lt;ul&gt;
      &lt;li&gt;例句：Life is beautiful. (生活是美好的。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;living room /ˈlɪvɪŋ ruːm/ 客厅
    &lt;ul&gt;
      &lt;li&gt;例句：We watch TV in the living room. (我们在客厅看电视。)&lt;/li&gt;
      &lt;li&gt;记忆：living（生活）+ room（房间）= living room（客厅）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bedroom /ˈbedruːm/ 卧室
    &lt;ul&gt;
      &lt;li&gt;例句：I sleep in my bedroom. (我在卧室睡觉。)&lt;/li&gt;
      &lt;li&gt;记忆：bed（床）+ room（房间）= bedroom（卧室）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;model plane /ˈmɒdəl pleɪn/ 飞机模型
    &lt;ul&gt;
      &lt;li&gt;例句：I have a model plane. (我有一个飞机模型。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;kitchen /ˈkɪtʃɪn/ 厨房
    &lt;ul&gt;
      &lt;li&gt;例句：My mother cooks in the kitchen. (我妈妈在厨房做饭。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bathroom /ˈbɑːθruːm/ 浴室；卫生间
    &lt;ul&gt;
      &lt;li&gt;例句：I brush my teeth in the bathroom. (我在浴室刷牙。)&lt;/li&gt;
      &lt;li&gt;记忆：bath（洗澡）+ room（房间）= bathroom（浴室）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;their /ðeə/ 他们的；她们的；它们的
    &lt;ul&gt;
      &lt;li&gt;例句：This is their book. (这是他们的书。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;light /laɪt/ 灯；光
    &lt;ul&gt;
      &lt;li&gt;例句：Turn on the light, please. (请开灯。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;watch /wɒtʃ/ 观看；观察
    &lt;ul&gt;
      &lt;li&gt;例句：I watch TV in the evening. (我晚上看电视。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;TV /ˌtiː ˈviː/ 电视；电视机
    &lt;ul&gt;
      &lt;li&gt;例句：I like watching TV. (我喜欢看电视。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;before /bɪˈfɔː/ 在……以前
    &lt;ul&gt;
      &lt;li&gt;例句：I do homework before dinner. (我在晚饭前做作业。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;bedtime /ˈbedtaɪm/ 就寝时间
    &lt;ul&gt;
      &lt;li&gt;例句：My bedtime is nine o’clock. (我的就寝时间是九点。)&lt;/li&gt;
      &lt;li&gt;记忆：bed（床）+ time（时间）= bedtime（就寝时间）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;do … homework /duː ˈhəʊmwɜːk/ 做家庭作业
    &lt;ul&gt;
      &lt;li&gt;例句：I do my homework every day. (我每天做家庭作业。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;turn off /tɜːn ɒf/ 关掉
    &lt;ul&gt;
      &lt;li&gt;例句：Turn off the light, please. (请关灯。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;watch TV /wɒtʃ ˌtiː ˈviː/ 看电视
    &lt;ul&gt;
      &lt;li&gt;例句：I watch TV after dinner. (我晚饭后看电视。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;tell a story /tel ə ˈstɔːri/ 讲故事
    &lt;ul&gt;
      &lt;li&gt;例句：My mother tells me a story. (我妈妈给我讲故事。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-7&quot;&gt;Unit 7&lt;/h2&gt;

&lt;p&gt;Title: At the beach Category: 度假类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;beach /biːtʃ/ 海滩
    &lt;ul&gt;
      &lt;li&gt;例句：We play on the beach. (我们在海滩上玩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;enjoy /ɪnˈdʒɔɪ/ 享受…的乐趣
    &lt;ul&gt;
      &lt;li&gt;例句：I enjoy reading books. (我喜欢读书。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sunshine /ˈsʌnʃaɪn/ 阳光
    &lt;ul&gt;
      &lt;li&gt;例句：We enjoy the sunshine on the beach. (我们在海滩享受阳光。)&lt;/li&gt;
      &lt;li&gt;记忆：sun（太阳）+ shine（照耀）= sunshine（阳光）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;collect /kəˈlekt/ 收集
    &lt;ul&gt;
      &lt;li&gt;例句：I collect shells. (我收集贝壳。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;shell /ʃel/ 贝壳
    &lt;ul&gt;
      &lt;li&gt;例句：I find a beautiful shell. (我找到一个漂亮的贝壳。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sea /siː/ 海
    &lt;ul&gt;
      &lt;li&gt;例句：The sea is blue. (大海是蓝色的。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;letter /ˈletə/ 信
    &lt;ul&gt;
      &lt;li&gt;例句：I write a letter to my friend. (我给我的朋友写信。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;put /pʊt/ 放；安置
    &lt;ul&gt;
      &lt;li&gt;例句：Put the book on the desk. (把书放在桌子上。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;know /nəʊ/ 知道
    &lt;ul&gt;
      &lt;li&gt;例句：I know the answer. (我知道答案。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;year /jɪə/ 年岁；年
    &lt;ul&gt;
      &lt;li&gt;例句：I am ten years old. (我十岁了。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;on holiday /ɒn ˈhɒlədi/ 度假
    &lt;ul&gt;
      &lt;li&gt;例句：We go to the beach on holiday. (我们度假时去海滩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;have a good time /hæv ə ɡʊd taɪm/ 玩得高兴
    &lt;ul&gt;
      &lt;li&gt;例句：We have a good time at the beach. (我们在海滩玩得很开心。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-8&quot;&gt;Unit 8&lt;/h2&gt;

&lt;p&gt;Title: An outing Category: 远足探险类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;outing /ˈaʊtɪŋ/ 远足
    &lt;ul&gt;
      &lt;li&gt;例句：We go on an outing. (我们去远足。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;map /mæp/ 地图
    &lt;ul&gt;
      &lt;li&gt;例句：I look at the map. (我看地图。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hill /hɪl/ 小山
    &lt;ul&gt;
      &lt;li&gt;例句：There is a hill over there. (那边有一座小山。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;find /faɪnd/ 发现；找到
    &lt;ul&gt;
      &lt;li&gt;例句：I find a key. (我找到一把钥匙。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;diamond /ˈdaɪəmənd/ 钻石
    &lt;ul&gt;
      &lt;li&gt;例句：The diamond is very beautiful. (钻石很漂亮。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;another /əˈnʌðə/ 另一个
    &lt;ul&gt;
      &lt;li&gt;例句：I want another apple. (我想要另一个苹果。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;lake /leɪk/ 湖
    &lt;ul&gt;
      &lt;li&gt;例句：The lake is very big. (这个湖很大。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;funny /ˈfʌni/ 滑稽的；好笑的
    &lt;ul&gt;
      &lt;li&gt;例句：This story is very funny. (这个故事很有趣。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hole /həʊl/ 洞
    &lt;ul&gt;
      &lt;li&gt;例句：There is a hole in the wall. (墙上有一个洞。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;key /kiː/ 钥匙
    &lt;ul&gt;
      &lt;li&gt;例句：This is the key to the door. (这是门的钥匙。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;think /θɪŋk/ 想
    &lt;ul&gt;
      &lt;li&gt;例句：I think it’s good. (我认为这很好。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;at the top of /æt ðə tɒp ɒv/ 在……顶部
    &lt;ul&gt;
      &lt;li&gt;例句：The flag is at the top of the hill. (旗子在山顶。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;get through /ɡet θruː/ 通过
    &lt;ul&gt;
      &lt;li&gt;例句：We get through the hole. (我们通过这个洞。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-9&quot;&gt;Unit 9&lt;/h2&gt;

&lt;p&gt;Title: Around the city Category: 方向类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;post office /pəʊst ˈɒfɪs/ 邮局
    &lt;ul&gt;
      &lt;li&gt;例句：I send a letter at the post office. (我在邮局寄信。)&lt;/li&gt;
      &lt;li&gt;记忆：post（邮政）+ office（办公室）= post office（邮局）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;quite /kwaɪt/ 相当；十分
    &lt;ul&gt;
      &lt;li&gt;例句：It’s quite good. (这相当好。)&lt;/li&gt;
      &lt;li&gt;记忆：quite（相当）和 quiet（安静的）容易混淆，quite 是副词&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;along /əˈlɒŋ/ 沿着；顺着
    &lt;ul&gt;
      &lt;li&gt;例句：Walk along this road. (沿着这条路走。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;turn /tɜːn/ 转向；转弯
    &lt;ul&gt;
      &lt;li&gt;例句：Turn left at the corner. (在拐角处向左转。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;left /left/ 左边
    &lt;ul&gt;
      &lt;li&gt;例句：The book is on the left. (书在左边。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;straight /streɪt/ 笔直地
    &lt;ul&gt;
      &lt;li&gt;例句：Go straight ahead. (一直往前走。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;right /raɪt/ 右边；正确的
    &lt;ul&gt;
      &lt;li&gt;例句：Turn right here. (在这里向右转。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;between /bɪˈtwiːn/ 在…中间
    &lt;ul&gt;
      &lt;li&gt;例句：The book is between two pens. (书在两支笔中间。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;flower shop /ˈflaʊə ʃɒp/ 花店
    &lt;ul&gt;
      &lt;li&gt;例句：My mother buys flowers at the flower shop. (我妈妈在花店买花。)&lt;/li&gt;
      &lt;li&gt;记忆：flower（花）+ shop（商店）= flower shop（花店）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hospital /ˈhɒspɪtəl/ 医院
    &lt;ul&gt;
      &lt;li&gt;例句：My father works in a hospital. (我爸爸在医院工作。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;toy shop /tɔɪ ʃɒp/ 玩具店
    &lt;ul&gt;
      &lt;li&gt;例句：I buy toys at the toy shop. (我在玩具店买玩具。)&lt;/li&gt;
      &lt;li&gt;记忆：toy（玩具）+ shop（商店）= toy shop（玩具店）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;road /rəʊd/ 路；马路
    &lt;ul&gt;
      &lt;li&gt;例句：This road is very long. (这条路很长。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;get to /ɡet tuː/ 到达
    &lt;ul&gt;
      &lt;li&gt;例句：How do I get to the school? (我怎么到学校？)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-10&quot;&gt;Unit 10&lt;/h2&gt;

&lt;p&gt;Title: Wind Category: 副词类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;blow /bləʊ/ 刮；吹
    &lt;ul&gt;
      &lt;li&gt;例句：The wind blows gently. (风轻轻地吹。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;gently /ˈdʒentli/ 和缓地；温柔地
    &lt;ul&gt;
      &lt;li&gt;例句：The wind blows gently. (风轻轻地吹。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;softly /ˈsɒftli/ 轻柔地
    &lt;ul&gt;
      &lt;li&gt;例句：She speaks softly. (她轻声说话。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;strongly /ˈstrɒŋli/ 强劲地
    &lt;ul&gt;
      &lt;li&gt;例句：The wind blows strongly. (风强劲地吹。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;happily /ˈhæpɪli/ 快乐地
    &lt;ul&gt;
      &lt;li&gt;例句：We play happily. (我们快乐地玩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;windmill /ˈwɪndmɪl/ 风车
    &lt;ul&gt;
      &lt;li&gt;例句：The windmill turns in the wind. (风车在风中转动。)&lt;/li&gt;
      &lt;li&gt;记忆：wind（风）+ mill（磨坊）= windmill（风车）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;move /muːv/ (使)改变位置；移动
    &lt;ul&gt;
      &lt;li&gt;例句：Don’t move! (别动！)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;slowly /ˈsləʊli/ 缓慢地
    &lt;ul&gt;
      &lt;li&gt;例句：The old man walks slowly. (老人慢慢地走。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;quickly /ˈkwɪkli/ 快地；迅速地
    &lt;ul&gt;
      &lt;li&gt;例句：I run quickly. (我跑得很快。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;sound /saʊnd/ 声乐；听起来好像
    &lt;ul&gt;
      &lt;li&gt;例句：It sounds good. (听起来不错。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;wind-bell /ˈwɪnd bel/ 风铃
    &lt;ul&gt;
      &lt;li&gt;例句：The wind-bell makes a nice sound. (风铃发出好听的声音。)&lt;/li&gt;
      &lt;li&gt;记忆：wind（风）+ bell（铃）= wind-bell（风铃）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;cut /kʌt/ 剪；砍；切
    &lt;ul&gt;
      &lt;li&gt;例句：I cut the paper. (我剪纸。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;paper /ˈpeɪpə/ 纸；纸张
    &lt;ul&gt;
      &lt;li&gt;例句：I write on paper. (我在纸上写字。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;quiet /ˈkwaɪət/ 轻声的；安静的
    &lt;ul&gt;
      &lt;li&gt;例句：Please be quiet. (请安静。)&lt;/li&gt;
      &lt;li&gt;记忆：quiet（安静的）和 quite（相当）容易混淆，quiet 是形容词&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-11&quot;&gt;Unit 11&lt;/h2&gt;

&lt;p&gt;Title: Water Category: 生活自然类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;tap /tæp/ 水龙头
    &lt;ul&gt;
      &lt;li&gt;例句：Turn on the tap. (打开水龙头。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;use /juːz/ 使用
    &lt;ul&gt;
      &lt;li&gt;例句：I use water to wash. (我用水来洗。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;vegetable /ˈvedʒtəbəl/ 蔬菜
    &lt;ul&gt;
      &lt;li&gt;例句：I like eating vegetables. (我喜欢吃蔬菜。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;clothes /kləʊðz/ 衣服；服装
    &lt;ul&gt;
      &lt;li&gt;例句：I wash my clothes. (我洗衣服。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;farmer /ˈfɑːmə/ 农民
    &lt;ul&gt;
      &lt;li&gt;例句：The farmer grows vegetables. (农民种蔬菜。)&lt;/li&gt;
      &lt;li&gt;记忆：farm（农场）+ er（人）= farmer（农民）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;useful /ˈjuːsfəl/ 有用的
    &lt;ul&gt;
      &lt;li&gt;例句：This book is very useful. (这本书很有用。)&lt;/li&gt;
      &lt;li&gt;记忆：use（使用）+ ful（充满的）= useful（有用的）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;drop /drɒp/ 滴；水珠
    &lt;ul&gt;
      &lt;li&gt;例句：A drop of water falls. (一滴水落下。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;up /ʌp/ 向上；在上面
    &lt;ul&gt;
      &lt;li&gt;例句：Look up! (向上看！)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;shine /ʃaɪn/ 照耀
    &lt;ul&gt;
      &lt;li&gt;例句：The sun shines. (太阳照耀。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;over /ˈəʊvə/ 在……上方
    &lt;ul&gt;
      &lt;li&gt;例句：The bridge is over the river. (桥在河上方。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;mountain /ˈmaʊntɪn/ 山；山脉
    &lt;ul&gt;
      &lt;li&gt;例句：The mountain is very high. (这座山很高。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;tree /triː/ 树
    &lt;ul&gt;
      &lt;li&gt;例句：There is a big tree. (有一棵大树。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;ground /ɡraʊnd/ 地面
    &lt;ul&gt;
      &lt;li&gt;例句：The apple falls to the ground. (苹果掉到地上。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;inside /ˌɪnˈsaɪd/ 在……里面
    &lt;ul&gt;
      &lt;li&gt;例句：The cat is inside the box. (猫在盒子里。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;grow crops /ɡrəʊ krɒps/ 种庄稼
    &lt;ul&gt;
      &lt;li&gt;例句：Farmers grow crops. (农民种庄稼。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;put out fires /pʊt aʊt ˈfaɪəz/ 灭火
    &lt;ul&gt;
      &lt;li&gt;例句：Firefighters put out fires. (消防员灭火。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;unit-12&quot;&gt;Unit 12&lt;/h2&gt;

&lt;p&gt;Title: Fire Category: 安全类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;fire /ˈfaɪə/ 火；火灾
    &lt;ul&gt;
      &lt;li&gt;例句：Fire is dangerous. (火是危险的。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;burn /bɜːn/ 燃烧；烧
    &lt;ul&gt;
      &lt;li&gt;例句：Don’t let the paper burn. (不要让纸烧起来。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hurt /hɜːt/ (使)受伤
    &lt;ul&gt;
      &lt;li&gt;例句：The fire can hurt you. (火会伤害你。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;must /mʌst/ 必须
    &lt;ul&gt;
      &lt;li&gt;例句：You must be careful. (你必须小心。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;careful /ˈkeəfəl/ 小心的
    &lt;ul&gt;
      &lt;li&gt;例句：Be careful with fire. (小心火。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;safety /ˈseɪfti/ 安全
    &lt;ul&gt;
      &lt;li&gt;例句：Safety is important. (安全很重要。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;smoke /sməʊk/ 吸烟
    &lt;ul&gt;
      &lt;li&gt;例句：Don’t smoke here. (不要在这里吸烟。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;match /mætʃ/ 火柴
    &lt;ul&gt;
      &lt;li&gt;例句：Don’t play with matches. (不要玩火柴。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;heat /hiːt/ 热；高温
    &lt;ul&gt;
      &lt;li&gt;例句：The heat is very strong. (热量很强。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;hate /heɪt/ 讨厌
    &lt;ul&gt;
      &lt;li&gt;例句：I hate fire. (我讨厌火。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;burn down /bɜːn daʊn/ 烧毁
    &lt;ul&gt;
      &lt;li&gt;例句：The fire can burn down the house. (火会烧毁房子。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;(be) careful with /biː ˈkeəfəl wɪð/ 当心……
    &lt;ul&gt;
      &lt;li&gt;例句：Be careful with fire. (小心火。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;not … at all /nɒt æt ɔːl/ 一点也不
    &lt;ul&gt;
      &lt;li&gt;例句：I don’t like it at all. (我一点也不喜欢它。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;英语六年级上册单词&quot;&gt;英语六年级上册单词&lt;/h1&gt;

&lt;h2 id=&quot;unit-1-1&quot;&gt;Unit 1&lt;/h2&gt;

&lt;p&gt;Title: Growing up Category: 成长变化类&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;month /mʌnθ/ 一个月的时间；月份
    &lt;ul&gt;
      &lt;li&gt;例句：There are twelve months in a year. (一年有十二个月。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;cute /kjuːt/ 可爱的
    &lt;ul&gt;
      &lt;li&gt;例句：The baby is very cute. (这个婴儿很可爱。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;pretty /ˈprɪti/ 漂亮的
    &lt;ul&gt;
      &lt;li&gt;例句：She is a pretty girl. (她是个漂亮的女孩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;handsome /ˈhænsəm/ 英俊的；帅气的
    &lt;ul&gt;
      &lt;li&gt;例句：He is a handsome boy. (他是个帅气的男孩。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;turtle /ˈtɜːtəl/ 乌龟
    &lt;ul&gt;
      &lt;li&gt;例句：I have a pet turtle. (我有一只宠物乌龟。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;catch /kætʃ/ 逮住；捕捉
    &lt;ul&gt;
      &lt;li&gt;例句：I catch a fly. (我捉住了一只苍蝇。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;fly /flaɪ/ 苍蝇
    &lt;ul&gt;
      &lt;li&gt;例句：There is a fly on the table. (桌子上有一只苍蝇。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;grow up /ɡrəʊ ʌp/ 长大；成长
    &lt;ul&gt;
      &lt;li&gt;例句：I want to grow up quickly. (我想快点长大。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;junior high school /ˈdʒuːniə haɪ skuːl/ 初级中学
    &lt;ul&gt;
      &lt;li&gt;例句：I will go to junior high school next year. (我明年将上初级中学。)&lt;/li&gt;
      &lt;li&gt;记忆：junior（初级的）+ high school（中学）= junior high school（初级中学）&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;(be) born /biː bɔːn/ 出生
    &lt;ul&gt;
      &lt;li&gt;例句：I was born in 2010. (我出生于2010年。)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="英语学习" /><summary type="html"></summary></entry><entry><title type="html">Protolint in Action</title><link href="http://172.19.0.16:8080/protocol%20buffers/2025/12/30/protolint-in-action.html" rel="alternate" type="text/html" title="Protolint in Action" /><published>2025-12-30T08:00:00+08:00</published><updated>2025-12-30T08:00:00+08:00</updated><id>http://172.19.0.16:8080/protocol%20buffers/2025/12/30/protolint-in-action</id><content type="html" xml:base="http://172.19.0.16:8080/protocol%20buffers/2025/12/30/protolint-in-action.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#基本用法&quot; id=&quot;markdown-toc-基本用法&quot;&gt;基本用法&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#查看所有规则&quot; id=&quot;markdown-toc-查看所有规则&quot;&gt;查看所有规则&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置规则&quot; id=&quot;markdown-toc-配置规则&quot;&gt;配置规则&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#方法-1-使用内联注释禁用规则推荐&quot; id=&quot;markdown-toc-方法-1-使用内联注释禁用规则推荐&quot;&gt;方法 1: 使用内联注释禁用规则（推荐）&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#方法-2-使用自动修复和禁用注释&quot; id=&quot;markdown-toc-方法-2-使用自动修复和禁用注释&quot;&gt;方法 2: 使用自动修复和禁用注释&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#方法-3-使用命令行参数&quot; id=&quot;markdown-toc-方法-3-使用命令行参数&quot;&gt;方法 3: 使用命令行参数&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#配置路径&quot; id=&quot;markdown-toc-配置路径&quot;&gt;配置路径&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#自动修复&quot; id=&quot;markdown-toc-自动修复&quot;&gt;自动修复&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#installation&quot; id=&quot;markdown-toc-installation&quot;&gt;Installation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#usage&quot; id=&quot;markdown-toc-usage&quot;&gt;Usage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#version-control-integration&quot; id=&quot;markdown-toc-version-control-integration&quot;&gt;Version Control Integration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#editor-integration&quot; id=&quot;markdown-toc-editor-integration&quot;&gt;Editor Integration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#call-from-go-code&quot; id=&quot;markdown-toc-call-from-go-code&quot;&gt;Call from Go code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#rules&quot; id=&quot;markdown-toc-rules&quot;&gt;Rules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#examples&quot; id=&quot;markdown-toc-examples&quot;&gt;Examples&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#enum_field_names_prefix&quot; id=&quot;markdown-toc-enum_field_names_prefix&quot;&gt;ENUM_FIELD_NAMES_PREFIX&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#enum_field_names_upper_snake_case&quot; id=&quot;markdown-toc-enum_field_names_upper_snake_case&quot;&gt;ENUM_FIELD_NAMES_UPPER_SNAKE_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#enum_field_names_zero_value_end_with&quot; id=&quot;markdown-toc-enum_field_names_zero_value_end_with&quot;&gt;ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#enum_names_upper_camel_case&quot; id=&quot;markdown-toc-enum_names_upper_camel_case&quot;&gt;ENUM_NAMES_UPPER_CAMEL_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#field_names_lower_snake_case&quot; id=&quot;markdown-toc-field_names_lower_snake_case&quot;&gt;FIELD_NAMES_LOWER_SNAKE_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#imports_sorted&quot; id=&quot;markdown-toc-imports_sorted&quot;&gt;IMPORTS_SORTED&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#message_names_upper_camel_case&quot; id=&quot;markdown-toc-message_names_upper_camel_case&quot;&gt;MESSAGE_NAMES_UPPER_CAMEL_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#order&quot; id=&quot;markdown-toc-order&quot;&gt;ORDER&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#package_name_lower_case&quot; id=&quot;markdown-toc-package_name_lower_case&quot;&gt;PACKAGE_NAME_LOWER_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#rpc_names_upper_camel_case&quot; id=&quot;markdown-toc-rpc_names_upper_camel_case&quot;&gt;RPC_NAMES_UPPER_CAMEL_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#rpc_services_upper_camel_case&quot; id=&quot;markdown-toc-rpc_services_upper_camel_case&quot;&gt;RPC_SERVICES_UPPER_CAMEL_CASE&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#repeated_field_names_pluralized&quot; id=&quot;markdown-toc-repeated_field_names_pluralized&quot;&gt;REPEATED_FIELD_NAMES_PLURALIZED&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#indent&quot; id=&quot;markdown-toc-indent&quot;&gt;INDENT&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#quote_consistent&quot; id=&quot;markdown-toc-quote_consistent&quot;&gt;QUOTE_CONSISTENT&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#creating-your-custom-rules&quot; id=&quot;markdown-toc-creating-your-custom-rules&quot;&gt;Creating your custom rules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#reporters&quot; id=&quot;markdown-toc-reporters&quot;&gt;Reporters&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#configure&quot; id=&quot;markdown-toc-configure&quot;&gt;Configure&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#disable-rules-in-a-protocol-buffer-file&quot; id=&quot;markdown-toc-disable-rules-in-a-protocol-buffer-file&quot;&gt;Disable rules in a Protocol Buffer file&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#config-file&quot; id=&quot;markdown-toc-config-file&quot;&gt;Config file&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#exit-codes&quot; id=&quot;markdown-toc-exit-codes&quot;&gt;Exit codes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; is the pluggable linting/fixing utility for Protocol Buffer files (proto2+proto3):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs fast&lt;/strong&gt; because this works without compiler.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy to follow the official style guide&lt;/strong&gt;. The rules and the style guide correspond to each other exactly.
    &lt;ul&gt;
      &lt;li&gt;Fixer automatically fixes all the possible official style guide violations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Allows to disable rules with a comment&lt;/strong&gt; in a Protocol Buffer file.
    &lt;ul&gt;
      &lt;li&gt;It is useful for projects which must keep API compatibility while enforce the style guide as much as possible.&lt;/li&gt;
      &lt;li&gt;Some rules can be automatically disabled by inserting comments to the spotted violations.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Loads plugins to contain your &lt;strong&gt;custom lint rules&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Undergone testing for all rules.&lt;/li&gt;
  &lt;li&gt;Many integration supports.
    &lt;ul&gt;
      &lt;li&gt;protoc plugin&lt;/li&gt;
      &lt;li&gt;Editor integration&lt;/li&gt;
      &lt;li&gt;GitHub Action&lt;/li&gt;
      &lt;li&gt;CI Integration&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;基本用法&quot;&gt;基本用法&lt;/h1&gt;

&lt;h2 id=&quot;查看所有规则&quot;&gt;查看所有规则&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;protolint list
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;常见规则：&lt;/p&gt;

&lt;p&gt;根据 &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint list&lt;/code&gt; 的输出，常用规则包括：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAX_LINE_LENGTH&lt;/code&gt;: 行长度限制（默认 80）&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;IMPORTS_SORTED&lt;/code&gt;: 导入排序&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;INDENT&lt;/code&gt;: 缩进风格&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SERVICE_NAMES_UPPER_CAMEL_CASE&lt;/code&gt;: 服务名大驼峰&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;RPC_NAMES_UPPER_CAMEL_CASE&lt;/code&gt;: RPC 方法名大驼峰&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MESSAGE_NAMES_UPPER_CAMEL_CASE&lt;/code&gt;: 消息名大驼峰&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;FIELD_NAMES_LOWER_SNAKE_CASE&lt;/code&gt;: 字段名小蛇形&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ENUM_FIELD_NAMES_UPPER_SNAKE_CASE&lt;/code&gt;: 枚举值名大蛇形&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;REPEATED_FIELD_NAMES_PLURALIZED&lt;/code&gt;: repeated 字段使用复数&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;配置规则&quot;&gt;配置规则&lt;/h2&gt;

&lt;h3 id=&quot;方法-1-使用内联注释禁用规则推荐&quot;&gt;方法 1: 使用内联注释禁用规则（推荐）&lt;/h3&gt;

&lt;p&gt;在 &lt;code class=&quot;highlighter-rouge&quot;&gt;.proto&lt;/code&gt; 文件中使用注释来禁用特定规则：&lt;/p&gt;

&lt;div class=&quot;language-protobuf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 在文件开头禁用 MAX_LINE_LENGTH 规则（项目规范是 120 字符）&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// protolint:disable MAX_LINE_LENGTH&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;proto3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;jmesh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 对于特定行，可以使用 :next 或 :this&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VeryLongMessageNameThatExceedsTheDefaultLineLengthLimit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// protolint:disable:next REPEATED_FIELD_NAMES_PLURALIZED&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;repeated&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// 这一行不会触发错误（:next 作用于下一行）&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;repeated&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// protolint:disable:this REPEATED_FIELD_NAMES_PLURALIZED 这一行不会触发错误（:this 作用于当前行）&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 重新启用规则&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// protolint:enable MAX_LINE_LENGTH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;方法-2-使用自动修复和禁用注释&quot;&gt;方法 2: 使用自动修复和禁用注释&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 自动修复可以修复的问题，并为其他问题插入禁用注释&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-fix&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-auto_disable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;next &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;方法-3-使用命令行参数&quot;&gt;方法 3: 使用命令行参数&lt;/h3&gt;

&lt;p&gt;某些规则可以通过命令行参数调整，例如：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看帮助&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;配置路径&quot;&gt;配置路径&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; 配置文件应放在 &lt;code class=&quot;highlighter-rouge&quot;&gt;protocol/.protolint.yaml&lt;/code&gt; 或项目根目录的 &lt;code class=&quot;highlighter-rouge&quot;&gt;.protolint.yaml&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;基本用法：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 在 protocol 目录下运行&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;protocol
protolint lint &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 在项目根目录运行，指定配置目录&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-config_dir_path&lt;/span&gt; protocol protocol/

&lt;span class=&quot;c&quot;&gt;# 指定配置文件路径&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-config_path&lt;/span&gt; protocol/.protolint.yaml protocol/mesh/protocol/route_registry.proto
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;自动修复&quot;&gt;自动修复&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 自动修复一些问题&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-fix&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 自动修复并插入禁用注释（推荐，保持兼容性）&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-fix&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-auto_disable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;next &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;installation&quot;&gt;Installation&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Via Homebrew
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; can be installed for Mac or Linux using Homebrew via the &lt;a href=&quot;https://github.com/yoheimuta/homebrew-protolint&quot;&gt;yoheimuta/protolint&lt;/a&gt; tap.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew tap yoheimuta/protolint
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;protolint
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Via GitHub Releases
    &lt;ul&gt;
      &lt;li&gt;You can also download a pre-built binary from this release page: https://github.com/yoheimuta/protolint/releases&lt;/li&gt;
      &lt;li&gt;In the downloads section of each release, you can find pre-built binaries in &lt;code class=&quot;highlighter-rouge&quot;&gt;.tar.gz packages&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use the maintained Docker image
    &lt;ul&gt;
      &lt;li&gt;protolint ships a Docker image &lt;a href=&quot;https://hub.docker.com/r/yoheimuta/protolint&quot;&gt;yoheimuta/protolint&lt;/a&gt; that allows you to use protolint as part of your Docker workflow.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯❯❯ docker run --volume &quot;$(pwd):/workspace&quot; --workdir /workspace yoheimuta/protolint lint _example/proto
[_example/proto/invalidFileName.proto:1:1] File name should be lower_snake_case.proto.
[_example/proto/issue_88/oneof_options.proto:11:5] Found an incorrect indentation style &quot;    &quot;. &quot;  &quot; is correct.
[_example/proto/issue_88/oneof_options.proto:12:5] Found an incorrect indentation style &quot;    &quot;. &quot;  &quot; is correct.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;From Source
    &lt;ul&gt;
      &lt;li&gt;The binary can be installed from source if Go is available. However, I recommend using one of the pre-built binaries instead because it doesn’t include the version info.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;github.com/yoheimuta/protolint/cmd/protolint@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Within &lt;code class=&quot;highlighter-rouge&quot;&gt;JavaScript&lt;/code&gt; / &lt;code class=&quot;highlighter-rouge&quot;&gt;TypeScript&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;You can use protolint using your nodejs package manager like &lt;code class=&quot;highlighter-rouge&quot;&gt;npm&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;protolint &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will add a reference to a development dependency to your local &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Within Python projects
    &lt;ul&gt;
      &lt;li&gt;You can use &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; as a linter within your python projects, the wheel &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint-bin&lt;/code&gt; on &lt;a href=&quot;https://pypi.org/&quot;&gt;pypi&lt;/a&gt; contains the pre-compiled binaries for various platforms. Just add the desired version to your &lt;code class=&quot;highlighter-rouge&quot;&gt;pyproject.toml&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;requirements.txt&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;The wheels downloaded will contain the compiled go binaries for &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;protoc-gen-protolint&lt;/code&gt;. Your platform must be compatible with the supported binary platforms.&lt;/li&gt;
      &lt;li&gt;You can add the linter configuration to the &lt;code class=&quot;highlighter-rouge&quot;&gt;tools.protolint&lt;/code&gt; package in &lt;code class=&quot;highlighter-rouge&quot;&gt;pyproject.toml&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/protolint.png&quot; alt=&quot;protolint&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; does not require configuration by default, for the majority of projects it should work out of the box.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;protolint lint example.proto example2.proto &lt;span class=&quot;c&quot;&gt;# file mode, specify multiple specific files&lt;/span&gt;
protolint lint &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;                            &lt;span class=&quot;c&quot;&gt;# directory mode, search for all .proto files recursively&lt;/span&gt;
protolint &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;                                 &lt;span class=&quot;c&quot;&gt;# same as &quot;protolint lint .&quot;&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-config_path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;path/to/your_protolint.yaml &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# use path/to/your_protolint.yaml&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-config_dir_path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;path/to &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# search path/to for .protolint.yaml&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-fix&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;                       &lt;span class=&quot;c&quot;&gt;# automatically fix some of the problems reported by some rules&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-fix&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-auto_disable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;next &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;# this is preferable when you want to fix problems while maintaining the compatibility. Automatically fix some problems and insert disable comments to the other problems. The available values are next and this.&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-auto_disable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;next &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;         &lt;span class=&quot;c&quot;&gt;# automatically insert disable comments to the other problems.&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;                         &lt;span class=&quot;c&quot;&gt;# with verbose output to investigate the parsing error&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-no-error-on-unmatched-pattern&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# exits with success code even if no file is found (file &amp;amp; directory mode)&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-reporter&lt;/span&gt; junit &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# output results in JUnit XML format&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-output_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;path/to/out.txt &lt;span class=&quot;c&quot;&gt;# output results to path/to/out.txt&lt;/span&gt;
protolint lint &lt;span class=&quot;nt&quot;&gt;-plugin&lt;/span&gt; ./my_custom_rule1 &lt;span class=&quot;nt&quot;&gt;-plugin&lt;/span&gt; ./my_custom_rule2 &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;# run custom lint rules.&lt;/span&gt;
protolint list                              &lt;span class=&quot;c&quot;&gt;# list all current lint rules being used&lt;/span&gt;
protolint version                           &lt;span class=&quot;c&quot;&gt;# print protolint version&lt;/span&gt;
protolint &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;                         &lt;span class=&quot;c&quot;&gt;# print protolint version (global flag)&lt;/span&gt;
protolint &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;                                &lt;span class=&quot;c&quot;&gt;# print protolint version (when used as the only argument)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;version-control-integration&quot;&gt;Version Control Integration&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; is available as a &lt;a href=&quot;https://pre-commit.com/&quot;&gt;pre-commit hook&lt;/a&gt;. Add this to your &lt;code class=&quot;highlighter-rouge&quot;&gt;.pre-commit-config.yaml&lt;/code&gt; in your repository to run protolint with Go:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;repos&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://github.com/yoheimuta/protolint&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;rev&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v0.56.3&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Select a release here&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hooks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;protolint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For Docker-based execution, use the &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint-docker&lt;/code&gt; hook:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;repos&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://github.com/yoheimuta/protolint&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hooks&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;protolint-docker&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Uses yoheimuta/protolint:latest by default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;editor-integration&quot;&gt;Editor Integration&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Visual Studio Code
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/plexsystems/vscode-protolint&quot;&gt;vscode-protolint&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=astryna-tools.protolint-vscode&quot;&gt;protolint-vscode&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;JetBrains IntelliJ IDEA, GoLand, WebStorm, PHPStorm, PyCharm…
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/yoheimuta/intellij-protolint&quot;&gt;intellij-protolint&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;call-from-go-code&quot;&gt;Call from Go code&lt;/h1&gt;

&lt;p&gt;You can also use &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; from Go code. See &lt;a href=&quot;https://pkg.go.dev/github.com/yoheimuta/protolint/lib&quot;&gt;Go Documentation&lt;/a&gt; and &lt;a href=&quot;https://github.com/yoheimuta/protolint/blob/master/lib/lint_test.go&quot;&gt;lib/lint_test.go&lt;/a&gt; in detail.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;bytes&quot;&lt;/span&gt;

    &lt;span class=&quot;s&quot;&gt;&quot;github.com/yoheimuta/protolint/lib&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-config_path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;path/to/your_protolint.yaml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Handle error&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Process output in stdout and stderr&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;rules&quot;&gt;Rules&lt;/h1&gt;

&lt;p&gt;See &lt;code class=&quot;highlighter-rouge&quot;&gt;internal/addon/rules&lt;/code&gt; in detail.&lt;/p&gt;

&lt;p&gt;The rule set follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://protobuf.dev/programming-guides/style/&quot;&gt;Official Style Guide&lt;/a&gt;. This is enabled by default. Basically, these rules can fix the violations by appending &lt;code class=&quot;highlighter-rouge&quot;&gt;-fix&lt;/code&gt; option.&lt;/li&gt;
  &lt;li&gt;Unofficial Style Guide. This is disabled by default. You can enable each rule with &lt;code class=&quot;highlighter-rouge&quot;&gt;.protolint.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-fix&lt;/code&gt; option on the command line can automatically fix all the problems reported by fixable rules. See Fixable columns below.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-auto_disable&lt;/code&gt; option on the command line can automatically disable all the problems reported by auto-disable rules. This feature is helpful when fixing the existing violations breaks the compatibility. See AutoDisable columns below.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I recommend that you add &lt;code class=&quot;highlighter-rouge&quot;&gt;all_default&lt;/code&gt;: true in &lt;code class=&quot;highlighter-rouge&quot;&gt;.protolint.yaml&lt;/code&gt;, because all linters above are automatically enabled so that you can always enjoy maximum benefits whenever protolint is updated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint list&lt;/code&gt; to see all available rules.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ protolint list
FILE_HAS_COMMENT: Verifies that a file starts with a doc comment.
SYNTAX_CONSISTENT: Verifies that syntax is a specified version(default is proto3).
FILE_NAMES_LOWER_SNAKE_CASE: Verifies that all file names are lower_snake_case.proto.
QUOTE_CONSISTENT: Verifies that the use of quote for strings is consistent.
ORDER: Verifies that all files should be ordered in the specific manner.
INDENT: Enforces a consistent indentation style.
MAX_LINE_LENGTH: Enforces a maximum line length.
PACKAGE_NAME_LOWER_CASE: Verifies that the package name doesn't contain any uppercase letters.
IMPORTS_SORTED: Enforces sorted imports.
ENUM_FIELD_NAMES_PREFIX: Verifies that enum field names are prefixed with its ENUM_NAME_UPPER_SNAKE_CASE.
ENUM_FIELD_NAMES_UPPER_SNAKE_CASE: Verifies that all enum field names are CAPITALS_WITH_UNDERSCORES.
ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH: Verifies that the zero value enum should have the suffix (e.g. &quot;UNSPECIFIED&quot;, &quot;INVALID&quot;).
ENUM_FIELDS_HAVE_COMMENT: Verifies that all enum fields have a comment.
ENUM_NAMES_UPPER_CAMEL_CASE: Verifies that all enum names are CamelCase (with an initial capital).
ENUMS_HAVE_COMMENT: Verifies that all enums have a comment.
FIELD_NAMES_LOWER_SNAKE_CASE: Verifies that all field names are underscore_separated_names.
FIELD_NAMES_EXCLUDE_PREPOSITIONS: Verifies that all field names don't include prepositions (e.g. &quot;for&quot;, &quot;during&quot;, &quot;at&quot;).
FIELDS_HAVE_COMMENT: Verifies that all fields have a comment.
PROTO3_FIELDS_AVOID_REQUIRED: Verifies that all fields should avoid required for proto3.
PROTO3_GROUPS_AVOID: Verifies that all groups should be avoided for proto3.
REPEATED_FIELD_NAMES_PLURALIZED: Verifies that repeated field names are pluralized names.
MESSAGE_NAMES_UPPER_CAMEL_CASE: Verifies that all message names are CamelCase (with an initial capital).
MESSAGE_NAMES_EXCLUDE_PREPOSITIONS: Verifies that all message names don't include prepositions (e.g. &quot;With&quot;, &quot;For&quot;).
MESSAGES_HAVE_COMMENT: Verifies that all messages have a comment.
RPC_NAMES_UPPER_CAMEL_CASE: Verifies that all rpc names are CamelCase (with an initial capital).
RPC_NAMES_CASE: Verifies that all rpc names conform to the specified convention.
RPCS_HAVE_COMMENT: Verifies that all rpcs have a comment.
SERVICE_NAMES_UPPER_CAMEL_CASE: Verifies that all service names are CamelCase (with an initial capital).
SERVICE_NAMES_END_WITH: Verifies that all service names end with the specified value.
SERVICES_HAVE_COMMENT: Verifies that all services have a comment.
FIELD_NUMBERS_ORDER_ASCENDING: Verifies the order of fields.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;examples&quot;&gt;Examples&lt;/h1&gt;

&lt;p&gt;Here are some examples that show good style enabled by default. &lt;code class=&quot;highlighter-rouge&quot;&gt;-&lt;/code&gt; is a bad style, &lt;code class=&quot;highlighter-rouge&quot;&gt;+&lt;/code&gt; is a good style:&lt;/p&gt;

&lt;h2 id=&quot;enum_field_names_prefix&quot;&gt;ENUM_FIELD_NAMES_PREFIX&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;enum FooBar {
-  UNSPECIFIED = 0;
+  FOO_BAR_UNSPECIFIED = 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;enum_field_names_upper_snake_case&quot;&gt;ENUM_FIELD_NAMES_UPPER_SNAKE_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;enum Foo {
-  firstValue = 0;
+  FIRST_VALUE = 0;
-  second_value = 1;
+  SECOND_VALUE = 1;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;enum_field_names_zero_value_end_with&quot;&gt;ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;enum Foo {
-  FOO_FIRST = 0;
+  FOO_UNSPECIFIED = 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考：https://github.com/yoheimuta/protolint/issues/256&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH&lt;/code&gt; conforms to &lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/style&quot;&gt;the style guide&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The zero value enum should have the suffix `UNSPECIFIED`.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/protolint2.png&quot; alt=&quot;protolint2&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;enum_names_upper_camel_case&quot;&gt;ENUM_NAMES_UPPER_CAMEL_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- enum foobar {
+ enum FooBar {
  FIRST_VALUE = 0;
  SECOND_VALUE = 1;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;field_names_lower_snake_case&quot;&gt;FIELD_NAMES_LOWER_SNAKE_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;message SongServerRequest {
-  required string SongName = 1;
+  required string song_name = 1;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;imports_sorted&quot;&gt;IMPORTS_SORTED&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- import public &quot;new.proto&quot;;
+ import &quot;myproject/other_protos.proto&quot;;
- import &quot;myproject/other_protos.proto&quot;;
+ import public &quot;new.proto&quot;;

import &quot;google/protobuf/empty.proto&quot;;
import &quot;google/protobuf/timestamp.proto&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;message_names_upper_camel_case&quot;&gt;MESSAGE_NAMES_UPPER_CAMEL_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- message song_server_request {
+ message SongServerRequest {
  required string SongName = 1;
  required string song_name = 1;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;order&quot;&gt;ORDER&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- option java_package = &quot;com.example.foo&quot;;
- syntax = &quot;proto3&quot;;
- package examplePb;
- message song_server_request { }
- import &quot;other.proto&quot;;
+ syntax = &quot;proto3&quot;;
+ package examplePb;
+ import &quot;other.proto&quot;;
+ option java_package = &quot;com.example.foo&quot;;
+ message song_server_request { }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;package_name_lower_case&quot;&gt;PACKAGE_NAME_LOWER_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- package myPackage
+ package my.package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rpc_names_upper_camel_case&quot;&gt;RPC_NAMES_UPPER_CAMEL_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;service FooService {
-  rpc get_something(FooRequest) returns (FooResponse);
+  rpc GetSomething(FooRequest) returns (FooResponse);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rpc_services_upper_camel_case&quot;&gt;RPC_SERVICES_UPPER_CAMEL_CASE&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- service foo_service {
+ service FooService {
  rpc get_something(FooRequest) returns (FooResponse);
  rpc GetSomething(FooRequest) returns (FooResponse);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;repeated_field_names_pluralized&quot;&gt;REPEATED_FIELD_NAMES_PLURALIZED&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-  repeated string song_name = 1;
+  repeated string song_names = 1;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;indent&quot;&gt;INDENT&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; enum enumAllowingAlias {
   UNKNOWN = 0;
-        option allow_alias = true;
+  option allow_alias = true;
   STARTED = 1;
-     RUNNING = 2 [(custom_option) = &quot;hello world&quot;];
+  RUNNING = 2 [(custom_option) = &quot;hello world&quot;];
- }
+}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-   message TestMessage { string test_field = 1; }
+ message TestMessage {
+  string test_field = 1;
+}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;quote_consistent&quot;&gt;QUOTE_CONSISTENT&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; option java_package = &quot;com.example.foo&quot;;
- option go_package = 'example';
+ option go_package = &quot;example&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;creating-your-custom-rules&quot;&gt;Creating your custom rules&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; is the pluggable linter so that you can freely create custom lint rules.&lt;/p&gt;

&lt;p&gt;A complete sample project (aka plugin) is included in this repo under the &lt;a href=&quot;https://github.com/yoheimuta/protolint/blob/master/_example/plugin&quot;&gt;_example/plugin&lt;/a&gt; directory.&lt;/p&gt;

&lt;h1 id=&quot;reporters&quot;&gt;Reporters&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; comes with several built-in reporters(aka. formatters) to control the appearance of the linting results.&lt;/p&gt;

&lt;p&gt;You can specify a reporter using the -reporter flag on the command line. For example, &lt;code class=&quot;highlighter-rouge&quot;&gt;-reporter junit&lt;/code&gt; uses the junit reporter.&lt;/p&gt;

&lt;p&gt;The built-in reporter options are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;plain (default)&lt;/li&gt;
  &lt;li&gt;junit&lt;/li&gt;
  &lt;li&gt;json&lt;/li&gt;
  &lt;li&gt;sarif&lt;/li&gt;
  &lt;li&gt;sonar (SonarQube generic issue format)&lt;/li&gt;
  &lt;li&gt;unix&lt;/li&gt;
  &lt;li&gt;tsc (compatible to TypeScript compiler)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;configure&quot;&gt;Configure&lt;/h1&gt;

&lt;h2 id=&quot;disable-rules-in-a-protocol-buffer-file&quot;&gt;Disable rules in a Protocol Buffer file&lt;/h2&gt;

&lt;p&gt;Rules can be disabled with a comment inside a Protocol Buffer file with the following format. The rules will be disabled until the end of the file or until the linter sees a matching enable comment:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// protolint:disable &amp;lt;ruleID1&amp;gt; [&amp;lt;ruleID2&amp;gt; &amp;lt;ruleID3&amp;gt;...]
...
// protolint:enable &amp;lt;ruleID1&amp;gt; [&amp;lt;ruleID2&amp;gt; &amp;lt;ruleID3&amp;gt;...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s also possible to modify a disable command by appending &lt;code class=&quot;highlighter-rouge&quot;&gt;:next&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;:this&lt;/code&gt; for only applying the command to this(current) or the next line respectively.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;enum Foo {
  // protolint:disable:next ENUM_FIELD_NAMES_UPPER_SNAKE_CASE
  firstValue = 0;    // no error
  second_value = 1;  // protolint:disable:this ENUM_FIELD_NAMES_UPPER_SNAKE_CASE
  THIRD_VALUE = 2;   // spits out an error
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setting the command-line option &lt;code class=&quot;highlighter-rouge&quot;&gt;-auto_disable&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;next&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;this&lt;/code&gt; inserts disable commands whenever spotting problems.&lt;/p&gt;

&lt;p&gt;You can specify &lt;code class=&quot;highlighter-rouge&quot;&gt;-fix&lt;/code&gt; option together. The rules supporting auto_disable suppress the violations instead of fixing them that cause a schema incompatibility.&lt;/p&gt;

&lt;h2 id=&quot;config-file&quot;&gt;Config file&lt;/h2&gt;

&lt;p&gt;protolint can operate using a config file named &lt;code class=&quot;highlighter-rouge&quot;&gt;.protolint.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Refer to &lt;a href=&quot;https://github.com/yoheimuta/protolint/blob/master/_example/config/.protolint.yaml&quot;&gt;_example/config/.protolint.yaml&lt;/a&gt; for the config file specification.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; will automatically search a current working directory for the config file by default and successive parent directories all the way up to the root directory of the filesystem. And it can search the specified directory with &lt;code class=&quot;highlighter-rouge&quot;&gt;-config_dir_path&lt;/code&gt; flag. It can also search the specified file with &lt;code class=&quot;highlighter-rouge&quot;&gt;--config_path&lt;/code&gt; flag.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Lint directives.&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;lint&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Linter files to ignore.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ignores&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MESSAGE_NAMES_UPPER_CAMEL_CASE&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# NOTE: UNIX paths will be properly accepted by both UNIX and Windows.&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;_example/proto/simple.proto&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ENUM_NAMES_UPPER_CAMEL_CASE&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path/to/foo.proto&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linter files to walk.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The specific files to exclude.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# NOTE: UNIX paths will be properly accepted by both UNIX and Windows.&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path/to/file&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linter directories to walk.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;directories&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# The specific directories to exclude.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# NOTE: UNIX paths will be properly accepted by both UNIX and Windows.&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;path/to/dir&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linter rules.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Run `protolint list` to see all available rules.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Determines whether or not to include the default set of linters.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;no_default&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Set the default to all linters. This option works the other way around as no_default does.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# If you want to enable this option, delete the comment out below and no_default.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# all_default: true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# The specific linters to add.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FIELD_NAMES_LOWER_SNAKE_CASE&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MESSAGE_NAMES_UPPER_CAMEL_CASE&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MAX_LINE_LENGTH&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;INDENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SERVICE_NAMES_END_WITH&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FIELD_NAMES_EXCLUDE_PREPOSITIONS&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MESSAGE_NAMES_EXCLUDE_PREPOSITIONS&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FILE_NAMES_LOWER_SNAKE_CASE&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;IMPORTS_SORTED&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PACKAGE_NAME_LOWER_CASE&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ORDER&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MESSAGES_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SERVICES_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RPCS_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FIELDS_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PROTO3_FIELDS_AVOID_REQUIRED&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PROTO3_GROUPS_AVOID&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;REPEATED_FIELD_NAMES_PLURALIZED&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ENUMS_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ENUM_FIELDS_HAVE_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SYNTAX_CONSISTENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RPC_NAMES_CASE&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FILE_HAS_COMMENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;QUOTE_CONSISTENT&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;FIELD_NUMBERS_ORDER_ASCENDING&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# The specific linters to remove.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RPC_NAMES_UPPER_CAMEL_CASE&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Linter rules option.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;rules_option&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# MAX_LINE_LENGTH rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;max_line_length&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Enforces a maximum line length&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;max_chars&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;80&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Specifies the character count for tab characters&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;tab_chars&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# INDENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Available styles are 4(4-spaces), 2(2-spaces) or tab.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Specifies if it should stop considering and inserting new lines at the appropriate positions&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# when the inner elements are on the same line. Default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;not_insert_newline&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# FILE_NAMES_LOWER_SNAKE_CASE rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;file_names_lower_snake_case&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;excludes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;../proto/invalidFileName.proto&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# QUOTE_CONSISTENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;quote_consistent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Available quote are &quot;double&quot; or &quot;single&quot;.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;double&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enum_field_names_zero_value_end_with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;INVALID&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# SERVICE_NAMES_END_WITH rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;service_names_end_with&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Service&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# FIELD_NAMES_EXCLUDE_PREPOSITIONS rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;field_names_exclude_prepositions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The specific prepositions to determine if the field name includes.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;prepositions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;for&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;at&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;of&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The specific keywords including prepositions to ignore. E.g. end_of_support is a term you would like to use, and skip checking.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;excludes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;end_of_support&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# REPEATED_FIELD_NAMES_PLURALIZED rule option.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;## The spec for each rules follows the implementation of https://github.com/gertd/go-pluralize.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;## Plus, you can refer to this rule's test code.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;repeated_field_names_pluralized&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;uncountable_rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;paper&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;irregular_rules&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Irregular&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Regular&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# MESSAGE_NAMES_EXCLUDE_PREPOSITIONS rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;message_names_exclude_prepositions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The specific prepositions to determine if the message name includes.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;prepositions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;With&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;For&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Of&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The specific keywords including prepositions to ignore. E.g. EndOfSupport is a term you would like to use, and skip checking.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;excludes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;EndOfSupport&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#  RPC_NAMES_CASE rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;rpc_names_case&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The specific convention the name should conforms to.&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;## Available conventions are &quot;lower_camel_case&quot;, &quot;upper_snake_case&quot;, or &quot;lower_snake_case&quot;.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;convention&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;upper_snake_case&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# MESSAGES_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;messages_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# SERVICES_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;services_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# RPCS_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;rpcs_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# FIELDS_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fields_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# ENUMS_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enums_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# ENUM_FIELDS_HAVE_COMMENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;enum_fields_have_comment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Comments need to begin with the name of the thing being described. default is false.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;should_follow_golang_style&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# SYNTAX_CONSISTENT rule option.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;syntax_consistent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Default is proto3.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;proto2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;exit-codes&quot;&gt;Exit codes&lt;/h1&gt;

&lt;p&gt;When linting files, &lt;code class=&quot;highlighter-rouge&quot;&gt;protolint&lt;/code&gt; will exit with one of the following exit codes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;: Linting was successful and there are no linting errors.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt;: Linting was successful and there is at least one linting error.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;2&lt;/code&gt;: Linting was unsuccessful due to all other errors, such as parsing, internal, and runtime errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;https://github.com/yoheimuta/protolint&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/style&quot;&gt;Style Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/proto3&quot;&gt;Language Guide (proto3)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/proto&quot;&gt;Language Guide (proto2)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/tutorials&quot;&gt;Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="Protocol Buffers" /><summary type="html"></summary></entry><entry><title type="html">Organizing a Go module</title><link href="http://172.19.0.16:8080/golang/2025/12/28/organizing-a-go-module.html" rel="alternate" type="text/html" title="Organizing a Go module" /><published>2025-12-28T12:00:00+08:00</published><updated>2025-12-28T12:00:00+08:00</updated><id>http://172.19.0.16:8080/golang/2025/12/28/organizing-a-go-module</id><content type="html" xml:base="http://172.19.0.16:8080/golang/2025/12/28/organizing-a-go-module.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#tutorial-create-a-go-module&quot; id=&quot;markdown-toc-tutorial-create-a-go-module&quot;&gt;Tutorial: Create a Go module&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#prerequisites&quot; id=&quot;markdown-toc-prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#start-a-module-that-others-can-use&quot; id=&quot;markdown-toc-start-a-module-that-others-can-use&quot;&gt;Start a module that others can use&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#call-your-code-from-another-module&quot; id=&quot;markdown-toc-call-your-code-from-another-module&quot;&gt;Call your code from another module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#managing-module-source&quot; id=&quot;markdown-toc-managing-module-source&quot;&gt;Managing module source&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#how-go-tools-find-your-published-module&quot; id=&quot;markdown-toc-how-go-tools-find-your-published-module&quot;&gt;How Go tools find your published module&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#organizing-code-in-the-repository&quot; id=&quot;markdown-toc-organizing-code-in-the-repository&quot;&gt;Organizing code in the repository&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#choosing-repository-scope&quot; id=&quot;markdown-toc-choosing-repository-scope&quot;&gt;Choosing repository scope&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#organizing-a-go-module&quot; id=&quot;markdown-toc-organizing-a-go-module&quot;&gt;Organizing a Go module&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#basic-package&quot; id=&quot;markdown-toc-basic-package&quot;&gt;Basic package&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#basic-command&quot; id=&quot;markdown-toc-basic-command&quot;&gt;Basic command&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#package-or-command-with-supporting-packages&quot; id=&quot;markdown-toc-package-or-command-with-supporting-packages&quot;&gt;Package or command with supporting packages&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#multiple-packages&quot; id=&quot;markdown-toc-multiple-packages&quot;&gt;Multiple packages&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#multiple-commands&quot; id=&quot;markdown-toc-multiple-commands&quot;&gt;Multiple commands&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#packages-and-commands-in-the-same-repository&quot; id=&quot;markdown-toc-packages-and-commands-in-the-same-repository&quot;&gt;Packages and commands in the same repository&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#server-project&quot; id=&quot;markdown-toc-server-project&quot;&gt;Server project&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common question developers new to Go have is “&lt;strong&gt;How do I organize my Go project?&lt;/strong&gt;”, in terms of the layout of files and folders. The goal of this document is to provide some guidelines that will help answer this question. &lt;strong&gt;To make the most of this document, make sure you’re familiar with the basics of Go modules by reading &lt;a href=&quot;https://go.dev/doc/tutorial/create-module&quot;&gt;Tutorial: Create a Go module&lt;/a&gt; and &lt;a href=&quot;https://go.dev/doc/modules/managing-source&quot;&gt;managing module source&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Go projects can include packages, command-line programs or a combination of the two. This guide is organized by project type.&lt;/p&gt;

&lt;h1 id=&quot;tutorial-create-a-go-module&quot;&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/create-module&quot;&gt;Tutorial: Create a Go module&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;This is the first part of a tutorial that introduces a few fundamental features of the Go language. If you’re just getting started with Go, be sure to take a look at &lt;a href=&quot;https://go.dev/doc/tutorial/getting-started.html&quot;&gt;Tutorial: Get started with Go&lt;/a&gt;, which introduces the go command, Go modules, and very simple Go code.&lt;/p&gt;

&lt;p&gt;In this tutorial you’ll create two modules. The first is a library which is intended to be imported by other libraries or applications. The second is a caller application which will use the first.&lt;/p&gt;

&lt;p&gt;This tutorial’s sequence includes seven brief topics that each illustrate a different part of the language.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a module – Write a small module with functions you can call from another module.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/call-module-code.html&quot;&gt;Call your code from another module&lt;/a&gt; – Import and use your new module.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/handle-errors.html&quot;&gt;Return and handle an error&lt;/a&gt; – Add simple error handling.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/random-greeting.html&quot;&gt;Return a random greeting&lt;/a&gt; – Handle data in slices (Go’s dynamically-sized arrays).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/greetings-multiple-people.html&quot;&gt;Return greetings for multiple people&lt;/a&gt; – Store key/value pairs in a map.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/add-a-test.html&quot;&gt;Add a test&lt;/a&gt; – Use Go’s built-in unit testing features to test your code.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/compile-install.html&quot;&gt;Compile and install the application&lt;/a&gt; – Compile and install your code locally.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: For other tutorials, see &lt;a href=&quot;https://go.dev/doc/tutorial/index.html&quot;&gt;Tutorials&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Some programming experience&lt;/strong&gt;. The code here is pretty simple, but it helps to know something about &lt;code class=&quot;highlighter-rouge&quot;&gt;functions&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;loops&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;arrays&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A tool to edit your code&lt;/strong&gt;. Any text editor you have will work fine. Most text editors have good support for Go. The most popular are &lt;code class=&quot;highlighter-rouge&quot;&gt;VSCode&lt;/code&gt; (free), &lt;code class=&quot;highlighter-rouge&quot;&gt;GoLand&lt;/code&gt; (paid), and &lt;code class=&quot;highlighter-rouge&quot;&gt;Vim&lt;/code&gt; (free).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;A command terminal&lt;/strong&gt;. Go works well using any terminal on Linux and Mac, and on PowerShell or cmd in Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;start-a-module-that-others-can-use&quot;&gt;Start a module that others can use&lt;/h2&gt;

&lt;p&gt;Start by creating a Go module. In a module, you collect one or more related packages for a discrete and useful set of functions. For example, you might create a module with packages that have functions for doing financial analysis so that others writing financial applications can use your work. For more about developing modules, see &lt;a href=&quot;https://go.dev/doc/modules/developing&quot;&gt;Developing and publishing modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go code is grouped into packages, and packages are grouped into modules. Your module specifies dependencies needed to run your code, including the Go version and the set of other modules it requires.&lt;/p&gt;

&lt;p&gt;As you add or improve functionality in your module, you publish new versions of the module. Developers writing code that calls functions in your module can import the module’s updated packages and test with the new version before putting it into production use.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Open a command prompt and cd to your home directory.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;On Linux or Mac:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On Windows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd %HOMEPATH%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Create a greetings directory for your Go module source code.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, from your home directory use the following commands:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir greetings
cd greetings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Start your module using the &lt;a href=&quot;https://go.dev/ref/mod#go-mod-init&quot;&gt;go mod init command&lt;/a&gt;.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run the &lt;code class=&quot;highlighter-rouge&quot;&gt;go mod init&lt;/code&gt; command, giving it your module path – here, use &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt;. If you publish a module, this must be a path from which your module can be downloaded by Go tools. That would be your code’s repository.&lt;/p&gt;

&lt;p&gt;For more on naming your module with a module path, see &lt;a href=&quot;https://go.dev/doc/modules/managing-dependencies#naming_module&quot;&gt;Managing dependencies&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go mod init example.com/greetings
go: creating new go.mod: module example.com/greetings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;go mod init&lt;/code&gt; command creates a &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file to track your code’s dependencies. So far, the file includes only the name of your module and the Go version your code supports. But as you add dependencies, the &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file will list the versions your code depends on. This keeps builds reproducible and gives you direct control over which module versions to use.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;In your text editor, create a file in which to write your code and call it &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings.go&lt;/code&gt;.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Paste the following code into your &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings.go&lt;/code&gt; file and save the file.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greetings&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Hello returns a greeting for the named person.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Return a greeting that embeds the name in a message.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hi, %v. Welcome!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the first code for your module. It returns a greeting to any caller that asks for one. You’ll write code that calls this function in the next step.&lt;/p&gt;

&lt;p&gt;In this code, you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Declare a greetings package to collect related functions.&lt;/li&gt;
  &lt;li&gt;Implement a Hello function to return the greeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This function takes a name parameter whose type is &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt;. The function also returns a &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt;. &lt;strong&gt;In Go, a function whose name starts with a capital letter can be called by a function not in the same package. This is known in Go as an exported name&lt;/strong&gt;. For more about exported names, see &lt;a href=&quot;https://go.dev/tour/basics/3&quot;&gt;Exported names&lt;/a&gt; in the Go tour.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/go-infra.png&quot; alt=&quot;go-infra&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Declare a message variable to hold your greeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Go, the &lt;code class=&quot;highlighter-rouge&quot;&gt;:=&lt;/code&gt; operator is a shortcut for declaring and initializing a variable in one line (Go uses the value on the right to determine the variable’s type). Taking the long way, you might have written this as:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hi, %v. Welcome!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Use the &lt;code class=&quot;highlighter-rouge&quot;&gt;fmt&lt;/code&gt; package’s &lt;a href=&quot;https://pkg.go.dev/fmt/#Sprintf&quot;&gt;Sprintf function&lt;/a&gt; to create a greeting message. The first argument is a format string, and &lt;code class=&quot;highlighter-rouge&quot;&gt;Sprintf&lt;/code&gt; substitutes the name parameter’s value for the &lt;code class=&quot;highlighter-rouge&quot;&gt;%v&lt;/code&gt; format verb. Inserting the value of the name parameter completes the greeting text.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Return the formatted greeting text to the caller.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In the next step, you’ll call this function from another module.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;call-your-code-from-another-module&quot;&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/call-module-code&quot;&gt;Call your code from another module&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;In the &lt;a href=&quot;https://go.dev/doc/tutorial/create-module.html&quot;&gt;previous section&lt;/a&gt;, you created a &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings&lt;/code&gt; &lt;strong&gt;module&lt;/strong&gt;. In this section, you’ll write code to make calls to the Hello function in the module you just wrote. You’ll write code you can execute as an application, and which calls code in the &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings&lt;/code&gt; module.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Create a &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; directory for your Go module source code. This is where you’ll write your caller.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;After you create this directory, you should have both a &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; and a &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings&lt;/code&gt; directory at the same level in the hierarchy, like so:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;home&amp;gt;/
 |-- greetings/
 |-- hello/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For example, if your command prompt is in the greetings directory, you could use the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;hello
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Enable dependency tracking for the code you’re about to write.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;To enable dependency tracking for your code, run the &lt;a href=&quot;https://go.dev/ref/mod#go-mod-init&quot;&gt;go mod init command&lt;/a&gt;, giving it the name of the module your code will be in.&lt;/p&gt;

&lt;p&gt;For the purposes of this tutorial, use &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; for the module path.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go mod init example.com/hello
go: creating new go.mod: module example.com/hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;In your text editor, in the &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; directory, create a file in which to write your code and call it &lt;code class=&quot;highlighter-rouge&quot;&gt;hello.go&lt;/code&gt;.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Write code to call the &lt;code class=&quot;highlighter-rouge&quot;&gt;Hello&lt;/code&gt; function, then print the function’s return value.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;To do that, paste the following code into &lt;code class=&quot;highlighter-rouge&quot;&gt;hello.go&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;example.com/greetings&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Get a greeting message and print it.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;greetings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Gladys&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this code, you:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Declare a &lt;code class=&quot;highlighter-rouge&quot;&gt;main&lt;/code&gt; package. In Go, code executed as an application must be in a &lt;code class=&quot;highlighter-rouge&quot;&gt;main&lt;/code&gt; package.&lt;/li&gt;
  &lt;li&gt;Import two packages: &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt; and the &lt;code class=&quot;highlighter-rouge&quot;&gt;fmt&lt;/code&gt; package. This gives your code access to functions in those packages. Importing &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt; (the package contained in the module you created earlier) gives you access to the &lt;code class=&quot;highlighter-rouge&quot;&gt;Hello&lt;/code&gt; function. You also import &lt;code class=&quot;highlighter-rouge&quot;&gt;fmt&lt;/code&gt;, with functions for handling input and output text (such as printing text to the console).&lt;/li&gt;
  &lt;li&gt;Get a greeting by calling the greetings package’s &lt;code class=&quot;highlighter-rouge&quot;&gt;Hello&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Edit the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; module to use your local &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt; module.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;For production use, you’d publish the example.com/greetings module from its repository (with a module path that reflected its published location), where Go tools could find it to download it&lt;/strong&gt;. For now, because you haven’t published the module yet, you need to adapt the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; module so it can find the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt; code on your local file system.&lt;/p&gt;

&lt;p&gt;To do that, use the go mod edit command to edit the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; module to redirect Go tools from its module path (where the module isn’t) to the local directory (where it is).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;From the command prompt in the &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; directory, run the following command:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go mod edit &lt;span class=&quot;nt&quot;&gt;-replace&lt;/span&gt; example.com/greetings&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;../greetings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The command specifies that &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt; should be replaced with &lt;code class=&quot;highlighter-rouge&quot;&gt;../greetings&lt;/code&gt; for the purpose of locating the dependency. After you run the command, the &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file in the hello directory should include a replace directive:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module example.com/hello

go 1.16

replace example.com/greetings =&amp;gt; ../greetings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;From the command prompt in the &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; directory, run the &lt;code class=&quot;highlighter-rouge&quot;&gt;go mod tidy&lt;/code&gt; command to synchronize the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; module’s dependencies, adding those required by the code, but not yet tracked in the module.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go mod tidy
go: found example.com/greetings &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;example.com/greetings v0.0.0-00010101000000-000000000000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the command completes, the &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; module’s &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file should look like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module example.com/hello

go 1.16

replace example.com/greetings =&amp;gt; ../greetings

require example.com/greetings v0.0.0-00010101000000-000000000000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The command found the local code in the greetings directory, then added a &lt;a href=&quot;https://go.dev/doc/modules/gomod-ref#require&quot;&gt;require directive&lt;/a&gt; to specify that &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/hello&lt;/code&gt; requires &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/greetings&lt;/code&gt;. You created this dependency when you imported the &lt;code class=&quot;highlighter-rouge&quot;&gt;greetings&lt;/code&gt; package in &lt;code class=&quot;highlighter-rouge&quot;&gt;hello.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The number following the module path is a pseudo-version number – a generated number used in place of a semantic version number (which the module doesn’t have yet).&lt;/p&gt;

&lt;p&gt;To reference a published module, a &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file would typically omit the &lt;code class=&quot;highlighter-rouge&quot;&gt;replace&lt;/code&gt; directive and use a require directive with a tagged version number at the end.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require example.com/greetings v1.1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For more on version numbers, see &lt;a href=&quot;https://go.dev/doc/modules/version-numbers&quot;&gt;Module version numbering&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;At the command prompt in the &lt;code class=&quot;highlighter-rouge&quot;&gt;hello&lt;/code&gt; directory, run your code to confirm that it works.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go run &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Hi, Gladys. Welcome!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Congrats! You’ve written two functioning modules.&lt;/p&gt;

&lt;h1 id=&quot;managing-module-source&quot;&gt;&lt;a href=&quot;https://go.dev/doc/modules/managing-source&quot;&gt;Managing module source&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;When you’re developing modules to publish for others to use, you can help ensure that your modules are easier for other developers to use by following the repository conventions described in this topic.&lt;/p&gt;

&lt;p&gt;This topic describes actions you might take when managing your module repository. For information about the sequence of workflow steps you’d take when revising from version to version, see &lt;a href=&quot;https://go.dev/doc/modules/release-workflow&quot;&gt;Module release and versioning workflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some of the conventions described here are required in modules, while others are best practices. This content assumes you’re familiar with the basic module use practices described in &lt;a href=&quot;https://go.dev/doc/modules/managing-dependencies&quot;&gt;Managing dependencies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go supports the following repositories for publishing modules: &lt;code class=&quot;highlighter-rouge&quot;&gt;Git&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Subversion&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Mercurial&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Bazaar&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;Fossil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For an overview of module development, see &lt;a href=&quot;https://go.dev/doc/modules/developing&quot;&gt;Developing and publishing modules&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;how-go-tools-find-your-published-module&quot;&gt;How Go tools find your published module&lt;/h2&gt;

&lt;p&gt;In Go’s decentralized system for publishing modules and retrieving their code, you can publish your module while leaving the code in your repository. Go tools rely on naming rules that have repository paths and repository tags indicating a module’s name and version number. When your repository follows these requirements, your module code is downloadable from your repository by Go tools such as the &lt;a href=&quot;https://go.dev/ref/mod#go-get&quot;&gt;go get command&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When a developer uses the &lt;code class=&quot;highlighter-rouge&quot;&gt;go get&lt;/code&gt; command to get source code for packages their code imports, the command does the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;From &lt;code class=&quot;highlighter-rouge&quot;&gt;import&lt;/code&gt; statements in Go source code, &lt;code class=&quot;highlighter-rouge&quot;&gt;go get&lt;/code&gt; identifies the module path within the package path.&lt;/li&gt;
  &lt;li&gt;Using a URL derived from the module path, the command locates the module source on a module proxy server or at its repository directly.&lt;/li&gt;
  &lt;li&gt;Locates source for the module version to download by matching the module’s version number to a repository tag to discover the code in the repository. When a version number to use is not yet known, go get locates the latest release version.&lt;/li&gt;
  &lt;li&gt;Retrieves module source and downloads it to the developer’s local module cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;organizing-code-in-the-repository&quot;&gt;Organizing code in the repository&lt;/h2&gt;

&lt;p&gt;You can keep maintenance simple and improve developers’ experience with your module by following the conventions described here. Getting your module code into a repository is generally as simple as with other code.&lt;/p&gt;

&lt;p&gt;The following diagram illustrates a source hierarchy for a simple module with two packages.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/go-infra2.png&quot; alt=&quot;go-infra2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Your initial commit should include files listed in the following table:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/go-infra3.png&quot; alt=&quot;go-infra3&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/gomod-ref&quot;&gt;go.mod file reference&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/managing-dependencies#naming_module&quot;&gt;Managing dependencies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the command-line, you can create an empty repository, add the files that will be part of your initial commit, and commit with a message. Here’s an example using &lt;code class=&quot;highlighter-rouge&quot;&gt;git&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git init
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git add &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mycode: initial commit&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;choosing-repository-scope&quot;&gt;Choosing repository scope&lt;/h2&gt;

&lt;p&gt;You publish code in a module when the code should be versioned independently from code in other modules.&lt;/p&gt;

&lt;p&gt;Designing your repository so that it hosts a single module at its root directory will help keep maintenance simpler, particularly over time as you publish new minor and patch versions, branch into new major versions, and so on. However, if your needs require it, you can instead maintain a collection of modules in a single repository.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sourcing one module per repository&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can maintain a repository that has a single module’s source in it. In this model, you place your go.mod file at the repository root, with package subdirectories containing Go source beneath.&lt;/p&gt;

&lt;p&gt;This is the simplest approach, making your module likely easier to manage over time. It helps you avoid the need to prefix a module version number with a directory path.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/go-infra4.png&quot; alt=&quot;go-infra4&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sourcing multiple modules in a single repository&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can publish multiple modules from a single repository. For example, you might have code in a single repository that constitutes multiple modules, but want to version those modules separately.&lt;/p&gt;

&lt;p&gt;Each subdirectory that is a module root directory must have its own &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Sourcing module code in subdirectories changes the form of the version tag you must use when publishing a module. You must prefix the version number part of the tag with the name of the subdirectory that is the module root. For more about version numbers, see &lt;a href=&quot;https://go.dev/doc/modules/version-numbers&quot;&gt;Module version numbering&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, for module &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/mymodules/module1&lt;/code&gt; below, you would have the following for version &lt;code class=&quot;highlighter-rouge&quot;&gt;v1.2.3&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Module path: &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/mymodules/module1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Version tag: &lt;code class=&quot;highlighter-rouge&quot;&gt;module1/v1.2.3&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Package path imported by a user: &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/mymodules/module1/package1&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Module path and version as specified in a user’s require directive: &lt;code class=&quot;highlighter-rouge&quot;&gt;example.com/mymodules/module1 v1.2.3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/go-infra5.png&quot; alt=&quot;go-infra5&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;organizing-a-go-module&quot;&gt;&lt;a href=&quot;https://go.dev/doc/modules/layout&quot;&gt;Organizing a Go module&lt;/a&gt;&lt;/h1&gt;

&lt;h2 id=&quot;basic-package&quot;&gt;Basic package&lt;/h2&gt;

&lt;p&gt;A basic Go package has all its code in the project’s root directory. The project consists of a single module, which consists of a single package. The package name matches the last path component of the module name. For a very simple package requiring a single Go file, the project structure is:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  modname.go
  modname_test.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assuming this directory is uploaded to a GitHub repository at &lt;code class=&quot;highlighter-rouge&quot;&gt;github.com/someuser/modname&lt;/code&gt;, the module line in the go.mod file should say module &lt;code class=&quot;highlighter-rouge&quot;&gt;github.com/someuser/modname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The code in &lt;code class=&quot;highlighter-rouge&quot;&gt;modname.go&lt;/code&gt; declares the package with:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modname&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ... package code here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Users can then rely on this package by import-ing it in their Go code with:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;github.com/someuser/modname&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A Go package can be split into multiple files, all residing within the same directory, e.g.:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth.go
  auth_test.go
  hash.go
  hash_test.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All the files in the directory declare package modname.&lt;/p&gt;

&lt;h2 id=&quot;basic-command&quot;&gt;Basic command&lt;/h2&gt;

&lt;p&gt;A basic executable program (or command-line tool) is structured according to its complexity and code size. The simplest program can consist of a single Go file where func main is defined. Larger programs can have their code split across multiple files, all declaring package main:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  auth.go
  auth_test.go
  client.go
  main.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here the &lt;code class=&quot;highlighter-rouge&quot;&gt;main.go&lt;/code&gt; file contains func main, but this is just a convention. The “main” file can also be called modname.go (for an appropriate value of modname) or anything else.&lt;/p&gt;

&lt;p&gt;Assuming this directory is uploaded to a GitHub repository at &lt;code class=&quot;highlighter-rouge&quot;&gt;github.com/someuser/modname&lt;/code&gt;, the module line in the &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; file should say:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module github.com/someuser/modname
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And a user should be able to install it on their machine with:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ go install github.com/someuser/modname@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;package-or-command-with-supporting-packages&quot;&gt;Package or command with supporting packages&lt;/h2&gt;

&lt;p&gt;Larger packages or commands may benefit from splitting off some functionality into supporting packages. Initially, it’s recommended placing such packages into a directory named internal; this prevents other modules from depending on packages we don’t necessarily want to expose and support for external uses. Since other projects cannot import code from our internal directory, we’re free to refactor its API and generally move things around without breaking external users. The project structure for a package is thus:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  internal/
    auth/
      auth.go
      auth_test.go
    hash/
      hash.go
      hash_test.go
  go.mod
  modname.go
  modname_test.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;modname.go&lt;/code&gt; file declares package modname, &lt;code class=&quot;highlighter-rouge&quot;&gt;auth.go&lt;/code&gt; declares package auth and so on. &lt;code class=&quot;highlighter-rouge&quot;&gt;modname.go&lt;/code&gt; can import the &lt;code class=&quot;highlighter-rouge&quot;&gt;auth&lt;/code&gt; package as follows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import &quot;github.com/someuser/modname/internal/auth&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The layout for a command with supporting packages in an &lt;code class=&quot;highlighter-rouge&quot;&gt;internal&lt;/code&gt; directory is very similar, except that the file(s) in the root directory declare package &lt;code class=&quot;highlighter-rouge&quot;&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;multiple-packages&quot;&gt;Multiple packages&lt;/h2&gt;

&lt;p&gt;A module can consist of multiple importable packages; each package has its own directory, and can be structured hierarchically. Here’s a sample project structure:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth/
    auth.go
    auth_test.go
    token/
      token.go
      token_test.go
  hash/
    hash.go
  internal/
    trace/
      trace.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a reminder, we assume that the module line in &lt;code class=&quot;highlighter-rouge&quot;&gt;go.mod&lt;/code&gt; says:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;module github.com/someuser/modname
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The modname package resides in the root directory, declares package modname and can be imported by users with:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import &quot;github.com/someuser/modname&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sub-packages can be imported by users as follows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import &quot;github.com/someuser/modname/auth&quot;
import &quot;github.com/someuser/modname/auth/token&quot;
import &quot;github.com/someuser/modname/hash&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Package &lt;code class=&quot;highlighter-rouge&quot;&gt;trace&lt;/code&gt; that resides in &lt;code class=&quot;highlighter-rouge&quot;&gt;internal/trace&lt;/code&gt; cannot be imported outside this module. It’s recommended to keep packages in &lt;code class=&quot;highlighter-rouge&quot;&gt;internal&lt;/code&gt; as much as possible.&lt;/p&gt;

&lt;h2 id=&quot;multiple-commands&quot;&gt;Multiple commands&lt;/h2&gt;

&lt;p&gt;Multiple programs in the same repository will typically have separate directories:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  internal/
    ... shared internal packages
  prog1/
    main.go
  prog2/
    main.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In each directory, the program’s Go files declare package &lt;code class=&quot;highlighter-rouge&quot;&gt;main&lt;/code&gt;. A top-level &lt;code class=&quot;highlighter-rouge&quot;&gt;internal&lt;/code&gt; directory can contain shared packages used by all commands in the repository.&lt;/p&gt;

&lt;p&gt;Users can install these programs as follows:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ go install github.com/someuser/modname/prog1@latest
$ go install github.com/someuser/modname/prog2@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A common convention is placing all commands in a repository into a &lt;code class=&quot;highlighter-rouge&quot;&gt;cmd&lt;/code&gt; directory; while this isn’t strictly necessary in a repository that consists only of commands, it’s very useful in a mixed repository that has both commands and importable packages, as we will discuss next.&lt;/p&gt;

&lt;h2 id=&quot;packages-and-commands-in-the-same-repository&quot;&gt;Packages and commands in the same repository&lt;/h2&gt;

&lt;p&gt;Sometimes a repository will provide both importable packages and installable commands with related functionality. Here’s a sample project structure for such a repository:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  modname.go
  modname_test.go
  auth/
    auth.go
    auth_test.go
  internal/
    ... internal packages
  cmd/
    prog1/
      main.go
    prog2/
      main.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assuming this module is called &lt;code class=&quot;highlighter-rouge&quot;&gt;github.com/someuser/modname&lt;/code&gt;, users can now both import packages from it:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import &quot;github.com/someuser/modname&quot;
import &quot;github.com/someuser/modname/auth&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And install programs from it:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ go install github.com/someuser/modname/cmd/prog1@latest
$ go install github.com/someuser/modname/cmd/prog2@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;server-project&quot;&gt;Server project&lt;/h2&gt;

&lt;p&gt;Go is a common language choice for implementing servers. There is a very large variance in the structure of such projects, given the many aspects of server development: protocols (&lt;code class=&quot;highlighter-rouge&quot;&gt;REST&lt;/code&gt;? &lt;code class=&quot;highlighter-rouge&quot;&gt;gRPC&lt;/code&gt;?), deployments, front-end files, containerization, scripts and so on. We will focus our guidance here on the parts of the project written in Go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server projects typically won’t have packages for export, since a server is usually a self-contained binary (or a group of binaries)&lt;/strong&gt;. Therefore, it’s recommended to keep the Go packages implementing the server’s logic in the internal directory. Moreover, since the project is likely to have many other directories with non-Go files, it’s a good idea to keep all Go commands together in a cmd directory:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-root-directory/
  go.mod
  internal/
    auth/
      ...
    metrics/
      ...
    model/
      ...
  cmd/
    api-server/
      main.go
    metrics-analyzer/
      main.go
    ...
  ... the project's other directories with non-Go code
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In case the server repository grows packages that become useful for sharing with other projects, it’s best to split these off to separate modules.&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/layout&quot;&gt;Organizing a Go module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/create-module&quot;&gt;Tutorial: Create a Go module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/call-module-code&quot;&gt;Call your code from another module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/managing-source&quot;&gt;Managing module source&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/release-workflow&quot;&gt;Module release and versioning workflow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/managing-dependencies&quot;&gt;Managing dependencies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/developing&quot;&gt;Developing and publishing modules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/tutorial/getting-started.html&quot;&gt;Tutorial: Get started with Go&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://go.dev/doc/modules/gomod-ref&quot;&gt;go.mod file reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="GoLang" /><summary type="html"></summary></entry><entry><title type="html">Being Confused About When To Use Generics</title><link href="http://172.19.0.16:8080/golang/2025/12/26/being-confused-about-when-to-use-generics.html" rel="alternate" type="text/html" title="Being Confused About When To Use Generics" /><published>2025-12-26T12:30:00+08:00</published><updated>2025-12-26T12:30:00+08:00</updated><id>http://172.19.0.16:8080/golang/2025/12/26/being-confused-about-when-to-use-generics</id><content type="html" xml:base="http://172.19.0.16:8080/golang/2025/12/26/being-confused-about-when-to-use-generics.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#concepts&quot; id=&quot;markdown-toc-concepts&quot;&gt;Concepts&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#common-uses-and-misuses&quot; id=&quot;markdown-toc-common-uses-and-misuses&quot;&gt;Common uses and misuses&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot; id=&quot;markdown-toc-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Generics&lt;/strong&gt; is a fresh addition to the language. In a nutshell, it allows writing code with types that can be specified later and instantiated when needed. However, it can be pretty easy to be confused about when to use generics and when not to. Throughout this post, we will describe the concept of generics in Go and then delve into common use and misuses.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;核心观点：依赖泛型和类型参数可以避免编写提取元素或行为的样板代码。但是，不要过早使用类型参数，只有在看到具体需要时才使用它们。否则，它们会引入不必要的抽象和复杂性。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;concepts&quot;&gt;Concepts&lt;/h1&gt;

&lt;p&gt;Consider the following function that extracts all the keys from a &lt;code class=&quot;highlighter-rouge&quot;&gt;map[string]int&lt;/code&gt; type:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What if we would like to use a similar feature for another map type such as a &lt;code class=&quot;highlighter-rouge&quot;&gt;map[int]string&lt;/code&gt;? &lt;strong&gt;Before generics, Go developers had a couple of options: using code generation, reflection, or duplicating code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, we could write two functions, one for each map type, or even try to extend &lt;code class=&quot;highlighter-rouge&quot;&gt;getKeys&lt;/code&gt; to accept different map types:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;unknown type: %T&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// Copy the extraction logic&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;We can start noticing a couple of issues:&lt;/strong&gt; (三个问题)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;First, it increases boilerplate code. Indeed, whenever we want to add a case, it will require duplicating the &lt;code class=&quot;highlighter-rouge&quot;&gt;range&lt;/code&gt; loop.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Meanwhile, the function now accepts an empty interface, which means we are losing some of the benefits of Go being a typed language. Indeed, checking whether a type is supported is done at runtime instead of compile-time. Hence, we also need to return an error if the provided type is unknown.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Last but not least, as the key type can be either &lt;code class=&quot;highlighter-rouge&quot;&gt;int&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt;, we are obliged to return a slice of empty interfaces to factor out key types. This approach increases the effort on the caller-side as the client may also have to perform a type check of the keys or extra conversion.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Thanks to generics, we can now refactor this code using type parameters.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type parameters are generic types we can use with &lt;strong&gt;functions&lt;/strong&gt; and &lt;strong&gt;types&lt;/strong&gt;. For example, the following function accepts a type parameter:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When calling &lt;code class=&quot;highlighter-rouge&quot;&gt;foo&lt;/code&gt;, we will pass a type argument of any type. Passing a type argument is called instantiation because the work is done at compile time which keeps type safety as part of the core language features and avoids runtime overheads.&lt;/p&gt;

&lt;p&gt;Let’s get back to the &lt;code class=&quot;highlighter-rouge&quot;&gt;getKeys&lt;/code&gt; function and use type parameters to write a generic version that would accept any kind of map:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To handle the map, we defined two kinds of type parameters. First, the values can be of any type: &lt;code class=&quot;highlighter-rouge&quot;&gt;V any&lt;/code&gt;. &lt;strong&gt;However, in Go, the map keys can’t be of any type&lt;/strong&gt;. For example, we cannot use &lt;strong&gt;slices&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code leads to a compilation error: &lt;strong&gt;invalid map key type []byte&lt;/strong&gt;. Therefore, instead of accepting any key type, we are obliged to restrict type arguments so that the key type meets specific requirements. Here, being comparable (we can use &lt;code class=&quot;highlighter-rouge&quot;&gt;==&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;!=&lt;/code&gt;). &lt;strong&gt;Hence, we defined &lt;code class=&quot;highlighter-rouge&quot;&gt;K&lt;/code&gt; as comparable instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Restricting type arguments to match specific requirements is called a &lt;strong&gt;constraint&lt;/strong&gt;. A constraint is an interface type that can contain:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A set of behaviors (methods)&lt;/li&gt;
  &lt;li&gt;But also arbitrary type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see a concrete example for the latter. Imagine we don’t want to accept any &lt;code class=&quot;highlighter-rouge&quot;&gt;comparable&lt;/code&gt; type for map key type. For instance, we would like to restrict it to either &lt;code class=&quot;highlighter-rouge&quot;&gt;int&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt; types. We can define a custom constraint this way:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customConstraint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;err&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Define a custom type that will restrict types to int and string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Change the type parameter K to be custom&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customConstraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;c&quot;&gt;// Same implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, we define a &lt;code class=&quot;highlighter-rouge&quot;&gt;customConstraint&lt;/code&gt; interface to restrict the types to be either &lt;code class=&quot;highlighter-rouge&quot;&gt;int&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt; using the union operator &lt;code class=&quot;highlighter-rouge&quot;&gt;|&lt;/code&gt; (we will discuss the use of &lt;code class=&quot;highlighter-rouge&quot;&gt;~&lt;/code&gt; a bit later). Then, &lt;code class=&quot;highlighter-rouge&quot;&gt;K&lt;/code&gt; is now a &lt;code class=&quot;highlighter-rouge&quot;&gt;customConstraint&lt;/code&gt; instead of a &lt;code class=&quot;highlighter-rouge&quot;&gt;comparable&lt;/code&gt; as before.&lt;/p&gt;

&lt;p&gt;Now, the signature of &lt;code class=&quot;highlighter-rouge&quot;&gt;getKeys&lt;/code&gt; enforces that we can call it with a map of any value type, but the key type has to be an &lt;code class=&quot;highlighter-rouge&quot;&gt;int&lt;/code&gt; or a &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt;. For example, on the caller-side:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;one&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;two&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;three&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that Go can infer that &lt;code class=&quot;highlighter-rouge&quot;&gt;getKeys&lt;/code&gt; is called with a &lt;code class=&quot;highlighter-rouge&quot;&gt;string&lt;/code&gt; type argument. The previous call was similar to this:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes9.png&quot; alt=&quot;100_go_mistakes9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s also note the &lt;code class=&quot;highlighter-rouge&quot;&gt;constraints&lt;/code&gt; package contains a set of common constraints such as &lt;code class=&quot;highlighter-rouge&quot;&gt;Signed&lt;/code&gt; that includes all the signed integer types. Let’s ensure that a constraint doesn’t already exist in this package before creating a new one.&lt;/p&gt;

&lt;p&gt;So far, we have discussed examples using generics for functions. &lt;strong&gt;However, we can also use generics with data structures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, we will create a linked list containing values of any type. Meanwhile, we will write an &lt;code class=&quot;highlighter-rouge&quot;&gt;Add&lt;/code&gt; method to append a node:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Use type parameter&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;Val&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Instantiate type receiver&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We use type parameters to define &lt;code class=&quot;highlighter-rouge&quot;&gt;T&lt;/code&gt; and use both fields in &lt;code class=&quot;highlighter-rouge&quot;&gt;Node&lt;/code&gt;. Regarding the method, the receiver is instantiated. Indeed, because &lt;code class=&quot;highlighter-rouge&quot;&gt;Node&lt;/code&gt; is &lt;strong&gt;generic&lt;/strong&gt;, it has to follow also the type parameter defined.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One last thing to note about type parameters: they can’t be used on &lt;code class=&quot;highlighter-rouge&quot;&gt;methods&lt;/code&gt;, only on &lt;code class=&quot;highlighter-rouge&quot;&gt;functions&lt;/code&gt;&lt;/strong&gt;. For example, the following method wouldn’t compile:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./main.go:29:15: methods cannot have type parameters
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, let’s delve into concrete cases where we should and shouldn’t use generics.&lt;/p&gt;

&lt;h1 id=&quot;common-uses-and-misuses&quot;&gt;Common uses and misuses&lt;/h1&gt;

&lt;p&gt;So when are &lt;strong&gt;generics&lt;/strong&gt; useful? Let’s discuss a couple of common uses &lt;strong&gt;where generics are recommended&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Data structures&lt;/strong&gt;. For example, we can use generics to factor out the element type if we implement a &lt;strong&gt;binary tree&lt;/strong&gt;, a &lt;strong&gt;linked list&lt;/strong&gt;, or a &lt;strong&gt;heap&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Functions working with slices, maps, and channels of any type&lt;/strong&gt;. For example, a function to merge two channels would work with any channel type. Hence, we could use type parameters to factor out the channel type:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Meanwhile, instead of factoring out a type, we can factor out behaviors&lt;/strong&gt;. For example, the sort package contains functions to sort different slice types such as &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Ints&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Float64s&lt;/code&gt;. Using type parameters, we can factor out the sorting behaviors that rely on three methods, &lt;code class=&quot;highlighter-rouge&quot;&gt;Len&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;Less&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;Swap&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Use type parameter&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;compare&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Compare two T elements&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Conversely, &lt;strong&gt;when is it recommended not to use generics&lt;/strong&gt;?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When just calling a method of the type argument. For example, consider a function that receives an &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; and call the &lt;code class=&quot;highlighter-rouge&quot;&gt;Write&lt;/code&gt; method:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;When it makes our code more complex. Generics are never &lt;strong&gt;mandatory&lt;/strong&gt;(强制性的), and as Go developers, we have been able to live without them for more than a decade. If writing generic functions or structures we figure out that it doesn’t make our code clearer, we should probably reconsider our decision for this particular use case.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Though generics can be very helpful in particular conditions, we should be cautious about when to use them and not use them.&lt;/p&gt;

&lt;p&gt;In general, when we want to answer when not to use generics, we can find similarities with when not to use interfaces. Indeed, generics introduce a form of abstraction, and we have to remember that unnecessary abstractions introduce complexity.&lt;/p&gt;

&lt;p&gt;Let’s not pollute our code with needless abstractions, and let’s focus on solving concrete problems for now. It means that we shouldn’t use type parameters prematurely. Let’s wait until we are about to write boilerplate code to consider using generics.&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://100go.co/9-generics/&quot;&gt;Being confused about when to use generics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://notebooklm.google.com/notebook/9bc436f4-4ba6-457d-bd58-b7b245730f25&quot;&gt;NotebookLM 笔记&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="GoLang" /><summary type="html"></summary></entry><entry><title type="html">How to Achieve Concurrency</title><link href="http://172.19.0.16:8080/golang/2025/12/25/how-to-achieve-concurrency.html" rel="alternate" type="text/html" title="How to Achieve Concurrency" /><published>2025-12-25T08:30:00+08:00</published><updated>2025-12-25T08:30:00+08:00</updated><id>http://172.19.0.16:8080/golang/2025/12/25/how-to-achieve-concurrency</id><content type="html" xml:base="http://172.19.0.16:8080/golang/2025/12/25/how-to-achieve-concurrency.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#并发的核心定义&quot; id=&quot;markdown-toc-并发的核心定义&quot;&gt;并发的核心定义&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#go-语言的两大核心并发特性&quot; id=&quot;markdown-toc-go-语言的两大核心并发特性&quot;&gt;Go 语言的两大核心并发特性&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#通道channels的工作机制&quot; id=&quot;markdown-toc-通道channels的工作机制&quot;&gt;通道（Channels）的工作机制&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#主要优势&quot; id=&quot;markdown-toc-主要优势&quot;&gt;主要优势&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#总结&quot; id=&quot;markdown-toc-总结&quot;&gt;总结&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;本文介绍了 Go 语言 如何通过其核心机制实现高效的并发编程。对比了传统同步处理文件的低效性，并展示了如何利用 Goroutines 这种轻量级线程来独立执行多个任务。为了管理这些并发操作，程序使用 Channels 作为数据通信的管道，在不同任务之间安全地传递结果。这种设计允许程序在数据准备就绪前自动阻塞等待，从而简化了复杂的异步逻辑。通过结合这两大特性，开发者可以更轻松地构建高性能且结构简洁的应用程序。&lt;/p&gt;

&lt;p&gt;传统的编程就像&lt;strong&gt;只有一个厨师的厨房&lt;/strong&gt;，他必须切完所有的菜才能开始炒菜，非常耗时。而 Go 语言的并发就像是&lt;strong&gt;请了一群助手（Goroutines）&lt;/strong&gt;，每个助手负责处理一样食材，并把处理好的食材通过一条&lt;strong&gt;传送带（Channels）&lt;/strong&gt;送到主厨面前。主厨不需要时刻盯着助手，他只需要在传送带末端等着，&lt;strong&gt;有食材送达时再继续下一步工作&lt;/strong&gt;，这大大提升了整个厨房的出菜速度。&lt;/p&gt;

&lt;h1 id=&quot;并发的核心定义&quot;&gt;并发的核心定义&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;并发（Concurrency）独立地处理多个任务&lt;/strong&gt;。相比于传统的同步执行（按顺序一个接一个地等待任务完成），并发可以显著提高处理 I/O 密集型任务（如读取文件）的效率。&lt;/p&gt;

&lt;h1 id=&quot;go-语言的两大核心并发特性&quot;&gt;Go 语言的两大核心并发特性&lt;/h1&gt;

&lt;p&gt;Go 语言通过内置的两个功能简化了异步编程：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Goroutines（协程）&lt;/strong&gt;：可以被视为一种极其高效的线程。通过在函数调用前使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;go&lt;/code&gt; 关键字，程序可以为每个任务启动一个 goroutine，从而实现并发执行。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Channels（通道）&lt;/strong&gt;：通道是用于在 goroutines 之间发送和接收数据的工具，它确保了数据流动的有序性。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;通道channels的工作机制&quot;&gt;通道（Channels）的工作机制&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;管道比喻&lt;/strong&gt;：来源将通道比作一根管道（Pipe），一端用于发送数据，另一端用于接收数据。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;自动同步功能&lt;/strong&gt;：通道不仅负责传递结果（如错误信息或成功标志），还起到了协调执行顺序的作用。当代码尝试从通道接收值时，它会自动进入等待状态，直到有数据到达才会继续执行，这保证了程序不会在任务完成前尝试打印结果,。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;主要优势&quot;&gt;主要优势&lt;/h1&gt;

&lt;p&gt;使用 goroutines 和 channels 可以极大简化应用程序中的异步编程，使开发者能够以更简单、更直观的方式编写高效的并发代码。&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;想象有这样一场接力赛&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;准备阶段&lt;/strong&gt;：明确要分头行动（并发概念）。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;起跑&lt;/strong&gt;：多名运动员（Goroutines）同时出发，不再排队等候。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;传递信息&lt;/strong&gt;：运动员通过接力棒（Channels）传递处理好的信息。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;终点汇总&lt;/strong&gt;：裁判（主程序）在终点线等待，只有接到接力棒时才会记录成绩（自动同步），确保不会在比赛结束前宣布结果。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm9.png&quot; alt=&quot;notebooklm9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm18.png&quot; alt=&quot;notebooklm18&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PfbFtY0aHbI&amp;amp;list=TLGGqdK3vOoML-EyNDEyMjAyNQ&quot;&gt;How to achieve concurrency&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;https://www.youtube.com/@golang&lt;/li&gt;
  &lt;li&gt;https://notebooklm.google.com/notebook/de556dc2-5421-4a1d-b3b0-d6f3b44ad564 (NotebookLM 解读)&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="GoLang" /><summary type="html"></summary></entry><entry><title type="html">100 Go Mistakes and How to Avoid Them</title><link href="http://172.19.0.16:8080/golang/2025/12/24/100-go-mistakes.html" rel="alternate" type="text/html" title="100 Go Mistakes and How to Avoid Them" /><published>2025-12-24T20:30:00+08:00</published><updated>2025-12-24T20:30:00+08:00</updated><id>http://172.19.0.16:8080/golang/2025/12/24/100-go-mistakes</id><content type="html" xml:base="http://172.19.0.16:8080/golang/2025/12/24/100-go-mistakes.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#code-and-project-organization&quot; id=&quot;markdown-toc-code-and-project-organization&quot;&gt;Code and Project Organization&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#1-unintended-variable-shadowing-变量遮蔽&quot; id=&quot;markdown-toc-1-unintended-variable-shadowing-变量遮蔽&quot;&gt;1. Unintended variable shadowing (变量遮蔽)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#2-unnecessary-nested-code-代码嵌套过深&quot; id=&quot;markdown-toc-2-unnecessary-nested-code-代码嵌套过深&quot;&gt;2. Unnecessary nested code (代码嵌套过深)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#3-misusing-init-functions-init-函数误用&quot; id=&quot;markdown-toc-3-misusing-init-functions-init-函数误用&quot;&gt;3. Misusing init functions (init 函数误用)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#4-overusing-getters-and-setters-过度使用-gettersetter&quot; id=&quot;markdown-toc-4-overusing-getters-and-setters-过度使用-gettersetter&quot;&gt;4. Overusing getters and setters (过度使用 Getter/Setter)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#5-interface-pollution-接口污染&quot; id=&quot;markdown-toc-5-interface-pollution-接口污染&quot;&gt;5. Interface pollution (接口污染)&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#concepts-interface&quot; id=&quot;markdown-toc-concepts-interface&quot;&gt;Concepts (interface)&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#when-to-use-interfaces&quot; id=&quot;markdown-toc-when-to-use-interfaces&quot;&gt;When to use interfaces&lt;/a&gt;            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#common-behavior&quot; id=&quot;markdown-toc-common-behavior&quot;&gt;Common behavior&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#decoupling&quot; id=&quot;markdown-toc-decoupling&quot;&gt;Decoupling&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#restricting-behavior&quot; id=&quot;markdown-toc-restricting-behavior&quot;&gt;Restricting behavior&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#interface-pollution&quot; id=&quot;markdown-toc-interface-pollution&quot;&gt;Interface pollution&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#分析解释&quot; id=&quot;markdown-toc-分析解释&quot;&gt;分析解释&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#6-interface-on-the-producer-side-生产者端接口&quot; id=&quot;markdown-toc-6-interface-on-the-producer-side-生产者端接口&quot;&gt;6. Interface on the producer side (生产者端接口)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#7-returning-interfaces-返回接口&quot; id=&quot;markdown-toc-7-returning-interfaces-返回接口&quot;&gt;7. Returning interfaces (返回接口)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#8-any-says-nothing-滥用-any-类型&quot; id=&quot;markdown-toc-8-any-says-nothing-滥用-any-类型&quot;&gt;8. any says nothing (滥用 any 类型)&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#为什么滥用-any-有害&quot; id=&quot;markdown-toc-为什么滥用-any-有害&quot;&gt;为什么滥用 &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt; 有害？&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#何时应该使用-any&quot; id=&quot;markdown-toc-何时应该使用-any&quot;&gt;何时应该使用 any？&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#使用-any-的安全模式&quot; id=&quot;markdown-toc-使用-any-的安全模式&quot;&gt;使用 any 的安全模式&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#替代方案使用泛型go-118&quot; id=&quot;markdown-toc-替代方案使用泛型go-118&quot;&gt;替代方案：使用泛型（Go 1.18+）&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#9-being-confused-about-when-to-use-generics-泛型使用不当&quot; id=&quot;markdown-toc-9-being-confused-about-when-to-use-generics-泛型使用不当&quot;&gt;9. Being confused about when to use generics (泛型使用不当)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#10-not-being-aware-of-the-possible-problems-with-type-embedding-类型嵌入风险&quot; id=&quot;markdown-toc-10-not-being-aware-of-the-possible-problems-with-type-embedding-类型嵌入风险&quot;&gt;10. Not being aware of the possible problems with type embedding (类型嵌入风险)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#11-not-using-the-functional-options-pattern-缺少函数选项模式&quot; id=&quot;markdown-toc-11-not-using-the-functional-options-pattern-缺少函数选项模式&quot;&gt;11. Not using the functional options pattern (缺少函数选项模式)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#12-project-misorganization-project-structure-and-package-organization-项目结构与包名管理&quot; id=&quot;markdown-toc-12-project-misorganization-project-structure-and-package-organization-项目结构与包名管理&quot;&gt;12. Project misorganization (project structure and package organization) (项目结构与包名管理)&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#项目结构组织方式&quot; id=&quot;markdown-toc-项目结构组织方式&quot;&gt;项目结构组织方式&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#包组织最佳实践&quot; id=&quot;markdown-toc-包组织最佳实践&quot;&gt;包组织最佳实践&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#项目结构模板示例&quot; id=&quot;markdown-toc-项目结构模板示例&quot;&gt;项目结构模板示例&lt;/a&gt;            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#标准-go-项目布局参考&quot; id=&quot;markdown-toc-标准-go-项目布局参考&quot;&gt;标准 Go 项目布局（参考）&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#微服务项目结构&quot; id=&quot;markdown-toc-微服务项目结构&quot;&gt;微服务项目结构&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#关键实践总结&quot; id=&quot;markdown-toc-关键实践总结&quot;&gt;关键实践总结&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#13-creating-utility-packages-避免使用通用无意义的包名&quot; id=&quot;markdown-toc-13-creating-utility-packages-避免使用通用无意义的包名&quot;&gt;13. Creating utility packages (避免使用通用、无意义的包名)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#14-ignoring-package-name-collisions-变量名与包名发生冲突&quot; id=&quot;markdown-toc-14-ignoring-package-name-collisions-变量名与包名发生冲突&quot;&gt;14. Ignoring package name collisions (变量名与包名发生冲突)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#15-missing-code-documentation-缺少代码文档&quot; id=&quot;markdown-toc-15-missing-code-documentation-缺少代码文档&quot;&gt;15. Missing code documentation (缺少代码文档)&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#必须文档化的内容&quot; id=&quot;markdown-toc-必须文档化的内容&quot;&gt;必须文档化的内容&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#go-文档的独特优势&quot; id=&quot;markdown-toc-go-文档的独特优势&quot;&gt;Go 文档的独特优势&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#文档生成工具链&quot; id=&quot;markdown-toc-文档生成工具链&quot;&gt;文档生成工具链&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#为什么-go-特别强调文档&quot; id=&quot;markdown-toc-为什么-go-特别强调文档&quot;&gt;为什么 Go 特别强调文档&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#16-not-using-linters-未使用-linters&quot; id=&quot;markdown-toc-16-not-using-linters-未使用-linters&quot;&gt;16. Not using linters (未使用 linters)&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#data-types&quot; id=&quot;markdown-toc-data-types&quot;&gt;Data Types&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#17-creating-confusion-with-octal-literals&quot; id=&quot;markdown-toc-17-creating-confusion-with-octal-literals&quot;&gt;17. Creating confusion with octal literals&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Source code and community space of 📖 100 Go Mistakes and How to Avoid Them, published by Manning in August 2022. Read online: &lt;a href=&quot;https://100go.co/&quot;&gt;100go.co&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, it’s also open to the community. If you believe that a common Go mistake should be added, please create an &lt;a href=&quot;https://github.com/teivah/100-go-mistakes/issues/new?assignees=&amp;amp;labels=community+mistake&amp;amp;template=community_mistake.md&amp;amp;title=&quot;&gt;issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes.png&quot; alt=&quot;100_go_mistakes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes2.png&quot; alt=&quot;100_go_mistakes2&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;code-and-project-organization&quot;&gt;Code and Project Organization&lt;/h1&gt;

&lt;h2 id=&quot;1-unintended-variable-shadowing-变量遮蔽&quot;&gt;1. Unintended variable shadowing (变量遮蔽)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Avoiding shadowed variables can help prevent mistakes like referencing the wrong variable or confusing readers.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Variable shadowing&lt;/strong&gt; occurs when a variable name is redeclared in an inner block, but this practice is prone to mistakes. Imposing a rule to forbid shadowed variables depends on personal taste. For example, sometimes it can be convenient to reuse an existing variable name like &lt;code class=&quot;highlighter-rouge&quot;&gt;err&lt;/code&gt; for errors. Yet, in general, we should remain cautious because we now know that we can face a scenario where the code compiles, but the variable that receives the value is not the one expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;代码示例：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;log&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDefaultClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDefaultClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDefaultClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDefaultClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createDefaultClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;问题解析：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在 &lt;code class=&quot;highlighter-rouge&quot;&gt;listing1()&lt;/code&gt; 中出现了变量遮蔽问题：&lt;code class=&quot;highlighter-rouge&quot;&gt;:=&lt;/code&gt; 操作符在 if 块内创建了新的局部变量 client，而不是修改外部的 client 变量。所以外部 client 始终是 nil。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listing1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 外部声明的 client 变量&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// 这里使用 := 重新声明了新的 client 和 err 变量&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClientWithTracing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 这里创建了新的 client 变量&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 打印的是内部 client&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 这里使用的是外部的 client，仍然是 nil！&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;优化方案：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;解决方案1：&lt;code class=&quot;highlighter-rouge&quot;&gt;listing2()&lt;/code&gt;。使用不同的变量名 &lt;code class=&quot;highlighter-rouge&quot;&gt;c&lt;/code&gt; 接收返回值，然后赋值给外部 &lt;code class=&quot;highlighter-rouge&quot;&gt;client&lt;/code&gt;，避免变量遮蔽，但需要额外的临时变量。&lt;/li&gt;
  &lt;li&gt;解决方案2：&lt;code class=&quot;highlighter-rouge&quot;&gt;listing3()&lt;/code&gt;。预先声明所有变量，使用赋值操作符 &lt;code class=&quot;highlighter-rouge&quot;&gt;=&lt;/code&gt; 而不是短声明 &lt;code class=&quot;highlighter-rouge&quot;&gt;:=&lt;/code&gt;，代码较冗长，错误处理重复。&lt;/li&gt;
  &lt;li&gt;最佳实践：&lt;code class=&quot;highlighter-rouge&quot;&gt;listing4()&lt;/code&gt;。预先声明变量，逻辑与错误处理分离，最简洁，避免重复代码。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;避免遮蔽的建议：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;使用 IDE 或 linter 工具检测遮蔽&lt;/li&gt;
  &lt;li&gt;考虑禁用变量遮蔽的代码规范&lt;/li&gt;
  &lt;li&gt;除非有明确理由，否则避免重用变量名&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-unnecessary-nested-code-代码嵌套过深&quot;&gt;2. Unnecessary nested code (代码嵌套过深)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Avoiding nested levels and keeping the happy path aligned on the left makes building a mental code model easier.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In general, the more nested levels a function requires, the more complex it is to read and understand. Let’s see some different applications of this rule to optimize our code for readability:&lt;/p&gt;

&lt;p&gt;When an &lt;code class=&quot;highlighter-rouge&quot;&gt;if&lt;/code&gt; block returns, we should omit the &lt;code class=&quot;highlighter-rouge&quot;&gt;else&lt;/code&gt; block in all cases. For example, we shouldn’t write:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instead, we omit the &lt;code class=&quot;highlighter-rouge&quot;&gt;else&lt;/code&gt; block like this:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can also follow this logic with a non-happy path:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;empty string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, an empty &lt;code class=&quot;highlighter-rouge&quot;&gt;s&lt;/code&gt; represents the non-happy path. Hence, we should flip the condition like so:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;empty string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Writing readable code is an important challenge for every developer. Striving to reduce the number of nested blocks, aligning the happy path on the left, and returning as early as possible are concrete means to improve our code’s readability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;代码示例：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;errors&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 反面示例&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;join1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;s1 is empty&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;s2 is empty&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concatenate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 建议用法&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;join2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;s1 is empty&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;s2 is empty&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concatenate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;concatenate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s2&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3-misusing-init-functions-init-函数误用&quot;&gt;3. Misusing init functions (init 函数误用)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;When initializing variables, remember that init functions have limited error handling and make state handling and testing more complex. In most cases, initializations should be handled as specific functions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An init function is a function used to initialize the state of an application. It takes no arguments and returns no result (a &lt;code class=&quot;highlighter-rouge&quot;&gt;func()&lt;/code&gt; function). When a package is initialized, all the constant and variable declarations in the package are evaluated. Then, the init functions are executed.&lt;/p&gt;

&lt;p&gt;Init functions can lead to some issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They can limit error management.&lt;/li&gt;
  &lt;li&gt;They can complicate how to implement tests (for example, an external dependency must be set up, which may not be necessary for the scope of unit tests).&lt;/li&gt;
  &lt;li&gt;If the initialization requires us to set a state, that has to be done through global variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We should be cautious with init functions. They can be helpful in some situations, however, such as defining static configuration. Otherwise, and in most cases, we should handle initializations through ad hoc functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;init 函数是 Go 语言中的特殊函数，用于包初始化：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;无参数，无返回值&lt;/li&gt;
  &lt;li&gt;在程序启动时自动执行&lt;/li&gt;
  &lt;li&gt;一个包可以有多个 init 函数，按声明顺序执行&lt;/li&gt;
  &lt;li&gt;执行时机：&lt;strong&gt;包级变量初始化后，main 函数执行前&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;示例1：多个 init 函数&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// main.go&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;github.com/teivah/100-go-mistakes/src/02-code-project-organization/3-init-functions/redis&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;init 1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 第二个执行&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;init 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 第三个执行&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// redis.go&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;redis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 第一个执行&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;执行顺序：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;导入 redis 包 → 执行 &lt;code class=&quot;highlighter-rouge&quot;&gt;redis.init()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;执行 main 包的 init 函数（按声明顺序）&lt;/li&gt;
  &lt;li&gt;执行 main 函数&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;redis
init 1
init 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;示例2：数据库连接初始化&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;database/sql&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;log&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DB&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 全局变量&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;dataSourceName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MYSQL_DATA_SOURCE_NAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mysql&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataSourceName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 错误处理受限&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 只能 panic，无法优雅处理&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 必须使用全局变量&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataSourceName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mysql&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dataSourceName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ping&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;init 函数的问题：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;init 函数错误处理受限。如果初始化失败，只能 panic，无法返回错误给调用者，程序直接崩溃&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 如果初始化失败，只能 panic&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 无法返回错误给调用者&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 程序直接崩溃&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 对比普通函数&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 可以返回错误，让调用者决定如何处理&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;connection failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;测试复杂化
    &lt;ul&gt;
      &lt;li&gt;自动执行，无法控制时机&lt;/li&gt;
      &lt;li&gt;依赖全局变量，测试相互影响&lt;/li&gt;
      &lt;li&gt;需要设置环境变量，测试配置复杂&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 测试时需要：go test -env &quot;MYSQL_DATA_SOURCE_NAME=...&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// 或者需要模拟全局状态&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;依赖全局变量
    &lt;ul&gt;
      &lt;li&gt;全局状态难以维护&lt;/li&gt;
      &lt;li&gt;并发安全问题&lt;/li&gt;
      &lt;li&gt;代码耦合度高&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DB&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 全局变量&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 必须用全局变量存储状态&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;执行顺序不可控&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 多个包的 init 函数执行顺序&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// 由导入依赖决定，不易理解和维护&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;init 函数的适用场景：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DefaultConfig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 初始化静态配置（无外部依赖）&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;DefaultConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;MaxConn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;合理用途：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;静态配置初始化&lt;/li&gt;
  &lt;li&gt;验证包级变量合理性&lt;/li&gt;
  &lt;li&gt;注册驱动（如 database/sql 驱动注册）&lt;/li&gt;
  &lt;li&gt;设置默认行为&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;不适合的情况：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 不适合：有外部依赖的初始化&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 从环境变量读取配置（可能有环境依赖）&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 连接数据库（可能失败，需要错误处理）&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 启动网络服务（应延迟初始化）&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;最佳实践建议：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;使用显式初始化函数&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 更好的方式&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DB&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 其他依赖&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MYSQL_DATA_SOURCE_NAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;init db: %w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 可控的错误处理&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 使用 app&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;依赖注入&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataSourceName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 可测试，可控制&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MYSQL_DATA_SOURCE_NAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// 优雅处理&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;配置对象模式&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;DBDataSource&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 其他配置&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 显式加载配置，可返回错误&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoadConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// 处理错误&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DBDataSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;总结：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;init 函数的主要问题：&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;错误处理能力差：只能 panic，无法优雅处理&lt;/li&gt;
  &lt;li&gt;测试困难：自动执行，依赖全局状态&lt;/li&gt;
  &lt;li&gt;隐式行为：代码逻辑不明显，维护困难&lt;/li&gt;
  &lt;li&gt;执行顺序依赖：由导入顺序决定，不易理解&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;建议：除非是简单的静态初始化，否则使用显式初始化函数，这样代码更清晰、更可测试、错误处理更完善。&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;4-overusing-getters-and-setters-过度使用-gettersetter&quot;&gt;4. Overusing getters and setters (过度使用 Getter/Setter)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Forcing the use of getters and setters isn’t idiomatic in Go. Being pragmatic and finding the right balance between efficiency and blindly following certain idioms should be the way to go.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data encapsulation refers to hiding the values or state of an object. Getters and setters are means to enable encapsulation by providing exported methods on top of unexported object fields.&lt;/p&gt;

&lt;p&gt;In Go, there is no automatic support for getters and setters as we see in some languages. It is also considered neither mandatory nor idiomatic to use getters and setters to access struct fields. We shouldn’t overwhelm our code with getters and setters on structs if they don’t bring any value. We should be pragmatic and strive to find the right balance between efficiency and following idioms that are sometimes considered indisputable in other programming paradigms.&lt;/p&gt;

&lt;p&gt;Remember that Go is a unique language designed for many characteristics, including simplicity. However, if we find a need for getters and setters or, as mentioned, foresee a future need while guaranteeing forward compatibility, there’s nothing wrong with using them.&lt;/p&gt;

&lt;p&gt;Go 语言的设计哲学强调简洁和实用，不强制使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;getter&lt;/code&gt; 和 &lt;code class=&quot;highlighter-rouge&quot;&gt;setter&lt;/code&gt;。这与 Java 等语言形成鲜明对比。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go 语言的独特设计：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;没有自动属性支持&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Java风格（自动属性）&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Go风格（直接访问或手动方法）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 直接导出，简单情况&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;访问控制通过大小写实现&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 导出字段（公开）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// 大写开头 - 公开访问&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Age&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;       &lt;span class=&quot;c&quot;&gt;// 大写开头 - 公开访问&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 非导出字段（私有）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// 小写开头 - 包内访问&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;       &lt;span class=&quot;c&quot;&gt;// 小写开头 - 包内访问&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;何时使用 Getter/Setter？&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;适合使用的情况1：需要验证逻辑&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BankAccount&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 私有，需要保护&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Getter&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BankAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Balance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Setter（带验证）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BankAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Deposit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;存款金额必须为正数&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BankAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Withdraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;取款金额必须为正数&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;余额不足&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;适合使用的情况2：需要计算或派生值&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Rectangle&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Getter（计算值）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Area&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Perimeter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;适合使用的情况3：需要延迟初始化或缓存&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ExpensiveResource&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RWMutex&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;loaded&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Getter（延迟加载）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpensiveResource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RLock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loaded&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RUnlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RUnlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 加写锁并加载&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loaded&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loadExpensiveData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loaded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;不需要使用的情况&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;简单数据传输对象（DTO）&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 直接导出字段更简洁&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 使用简单明了&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Point: (%d, %d)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;配置结构&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Host&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;MaxConns&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 直接初始化更清晰&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;MaxConns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;内部辅助结构&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 只在包内使用，可以直接访问&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;internalState&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lastUpdate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Time&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;active&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;internalState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastUpdate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;总结建议&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;默认直接导出字段：Go 社区倾向于简单直接的访问方式&lt;/li&gt;
  &lt;li&gt;有理由时才封装：
    &lt;ul&gt;
      &lt;li&gt;需要验证逻辑&lt;/li&gt;
      &lt;li&gt;需要维护不变性&lt;/li&gt;
      &lt;li&gt;需要派生计算值&lt;/li&gt;
      &lt;li&gt;涉及并发安全&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;保持 API 稳定：如果结构体是公开 API 的一部分，提前考虑是否需要封装&lt;/li&gt;
  &lt;li&gt;信任使用者：Go 哲学假设开发者知道自己在做什么，不过度保护&lt;/li&gt;
  &lt;li&gt;文档说明：通过文档说明约束，而不是强制封装&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go 语言的这种务实态度正是其魅力所在——&lt;strong&gt;在简洁性和封装性之间找到平衡，避免不必要的复杂性&lt;/strong&gt;。&lt;/p&gt;

&lt;h2 id=&quot;5-interface-pollution-接口污染&quot;&gt;5. Interface pollution (接口污染)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Abstractions should be discovered, not created. To prevent unnecessary complexity, create an interface when you need it and not when you foresee needing it, or if you can at least prove the abstraction to be a valid one.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;More: &lt;a href=&quot;https://100go.co/5-interface-pollution/&quot;&gt;Interface pollution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;NotebookML 解读：https://notebooklm.google.com/notebook/d86b149b-bc4d-4587-9a75-7083db063b62?authuser=1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt; are one of the cornerstones(基石) of the Go language when designing and structuring our code. However, like many tools or concepts, abusing them is generally not a good idea. &lt;strong&gt;Interface pollution&lt;/strong&gt; is about overwhelming our code with unnecessary abstractions, making it harder to understand. It’s a common mistake made by developers coming from another language with different habits. Before delving into the topic, let’s refresh our minds about Go’s interfaces. Then, we will see when it’s appropriate to use interfaces and when it may be considered pollution.&lt;/p&gt;

&lt;p&gt;Go 语言中 “接口污染” 的概念，即过度或不必要地使用接口，反而会让代码变得复杂难懂。&lt;strong&gt;核心观点是：接口的抽象应该是“被发现”，而不是“被创造”。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;concepts-interface&quot;&gt;Concepts (interface)&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;interface&lt;/strong&gt; provides a way to specify the behavior of an object. We use interfaces to create common abstractions that multiple objects can implement. What makes Go interfaces so different is that they are satisfied implicitly. There is no explicit keyword like implements to mark that an object &lt;code class=&quot;highlighter-rouge&quot;&gt;X&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;implements&lt;/code&gt; interface &lt;code class=&quot;highlighter-rouge&quot;&gt;Y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To understand what makes interfaces so powerful, we will dig into two popular ones from the standard library: &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt;. The &lt;code class=&quot;highlighter-rouge&quot;&gt;io&lt;/code&gt; package provides abstractions for I/O primitives. Among these abstractions, &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; relates to reading data from a data source and &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; to writing data to a target, as represented in the next figure:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes3.png&quot; alt=&quot;100_go_mistakes3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; contains a single Read method:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Custom implementations of the &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; interface should accept a slice of bytes, filling it with its data and returning either the number of bytes read or an error.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; defines a single method, Write:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Custom implementations of &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; should write the data coming from a slice to a target and return either the number of bytes written or an error. &lt;strong&gt;Therefore, both interfaces provide fundamental abstractions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; reads data from a source&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; writes data to a target&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is the rationale(根本原因) for having these two interfaces in the language? What is the point of creating these abstractions?&lt;/p&gt;

&lt;p&gt;Let’s assume we need to implement a function that should copy the content of one file to another. We could create a specific function that would take as input two &lt;code class=&quot;highlighter-rouge&quot;&gt;*os.File&lt;/code&gt;. Or, we can choose to create a more generic function using &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; abstractions:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;copySourceToDest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function would work with &lt;code class=&quot;highlighter-rouge&quot;&gt;*os.File&lt;/code&gt; parameters (as &lt;code class=&quot;highlighter-rouge&quot;&gt;*os.File&lt;/code&gt; implements both &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt;) and any other type that would implement these interfaces. For example, we could create our own &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; that writes to a database, and the code would remain the same. &lt;strong&gt;It increases the genericity of the function; hence, its reusability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Furthermore, writing a unit test for this function is easier&lt;/strong&gt; because, instead of having to handle files, we can use the strings and bytes packages that provide helpful implementations:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestCopySourceToDest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Creates an io.Reader&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Creates an io.Writer&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;copySourceToDest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Calls copySourceToDest from a *strings.Reader and a *bytes.Buffer&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FailNow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;expected: %s, got: %s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the example, source is a &lt;code class=&quot;highlighter-rouge&quot;&gt;*strings.Reader&lt;/code&gt;, whereas dest is a &lt;code class=&quot;highlighter-rouge&quot;&gt;*bytes.Buffer&lt;/code&gt;. &lt;strong&gt;Here, we test the behavior of copySourceToDest without creating any files&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While designing interfaces, the &lt;strong&gt;granularity&lt;/strong&gt;(粒度) (&lt;strong&gt;how many methods the interface contains&lt;/strong&gt;) is also something to keep in mind. A &lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=318s&quot;&gt;known proverb&lt;/a&gt; in Go relates to how big an interface should be:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes4.png&quot; alt=&quot;100_go_mistakes4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Indeed, adding methods to an interface can decrease its level of reusability. &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt; are powerful abstractions because they cannot get any simpler. &lt;strong&gt;Furthermore, we can also combine fine-grained interfaces to create higher-level abstractions&lt;/strong&gt;. This is the case with &lt;code class=&quot;highlighter-rouge&quot;&gt;io.ReadWriter&lt;/code&gt;, which combines the reader and writer behaviors:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ReadWriter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes5.png&quot; alt=&quot;100_go_mistakes5&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;when-to-use-interfaces&quot;&gt;When to use interfaces&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;When should we create interfaces in Go?&lt;/strong&gt; Let’s look at three concrete use cases where interfaces are usually considered to bring value. Note that the goal isn’t to be exhaustive(详尽无遗的) because the more cases we add, the more they would depend on the context. &lt;strong&gt;However, these three cases should give us a general idea&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Common behavior&lt;/li&gt;
  &lt;li&gt;Decoupling&lt;/li&gt;
  &lt;li&gt;Restricting behavior&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;common-behavior&quot;&gt;Common behavior&lt;/h4&gt;

&lt;p&gt;The first option we will discuss is to use interfaces when multiple types implement a common behavior. In such a case, we can factor out the behavior inside an interface. If we look at the standard library, we can find many examples of such a use case. For example, sorting a collection can be factored out via three methods:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Retrieving the number of elements in the collection&lt;/li&gt;
  &lt;li&gt;Reporting whether one element must be sorted before another&lt;/li&gt;
  &lt;li&gt;Swapping two elements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, the following interface was added to the &lt;code class=&quot;highlighter-rouge&quot;&gt;sort&lt;/code&gt; package:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Interface&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Number of elements&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Checks two elements&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Swaps two elements&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This interface has a strong potential for reusability because it encompasses the common behavior to sort any collection that is index-based.&lt;/p&gt;

&lt;p&gt;Throughout the &lt;code class=&quot;highlighter-rouge&quot;&gt;sort&lt;/code&gt; package, we can find dozens of implementations. If at some point we compute a collection of integers, for example, and we want to sort it, are we necessarily interested in the implementation type? &lt;strong&gt;Is it important whether the sorting algorithm is a merge sort or a quicksort? In many cases, we don’t care.&lt;/strong&gt; Hence, the sorting behavior can be abstracted, and we can depend on the &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Interface&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finding the right abstraction to factor out a behavior can also bring many benefits. For example, the &lt;code class=&quot;highlighter-rouge&quot;&gt;sort&lt;/code&gt; package provides utility functions that also rely on &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Interface&lt;/code&gt;, such as checking whether a collection is already sorted. For instance:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IsSorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Interface&lt;/code&gt; is the right level of abstraction, it makes it highly valuable.&lt;/p&gt;

&lt;h4 id=&quot;decoupling&quot;&gt;Decoupling&lt;/h4&gt;

&lt;p&gt;Another important use case is about decoupling our code from an implementation. If we rely on an abstraction instead of a concrete implementation, the implementation itself can be replaced with another without even having to change our code. This is the Liskov Substitution Principle (the L in Robert C. Martin’s &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt; design principles).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Single-responsibility_principle&quot;&gt;Single responsibility&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle&quot;&gt;Open–closed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov substitution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Interface_segregation_principle&quot;&gt;Interface segregation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_inversion_principle&quot;&gt;Dependency inversion&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;In &lt;a href=&quot;https://en.wikipedia.org/wiki/Object-oriented_programming&quot;&gt;object-oriented programming&lt;/a&gt;, &lt;strong&gt;SOLID&lt;/strong&gt; is a mnemonic acronym for five principles intended to make source code more understandable, flexible, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_maintenance&quot;&gt;maintainable&lt;/a&gt;. Although the principles apply to object-oriented programming, they can also form a core philosophy for methodologies such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Agile_software_development&quot;&gt;agile software development&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Adaptive_software_development&quot;&gt;adaptive software development&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One benefit of decoupling can be related to unit testing. Let’s assume we want to implement a &lt;code class=&quot;highlighter-rouge&quot;&gt;CreateNewCustomer&lt;/code&gt; method that creates a new customer and stores it. We decide to rely on the concrete implementation directly (let’s say a &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql.Store&lt;/code&gt; struct):&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mysql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Store&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Depends on the concrete implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateNewCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StoreCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, what if we want to test this method? Because &lt;code class=&quot;highlighter-rouge&quot;&gt;customerService&lt;/code&gt; relies on the actual implementation to store a &lt;code class=&quot;highlighter-rouge&quot;&gt;Customer&lt;/code&gt;, we are obliged to test it through integration tests, which requires spinning up a MySQL instance (unless we use an alternative technique such as &lt;a href=&quot;https://github.com/DATA-DOG/go-sqlmock&quot;&gt;go-sqlmock&lt;/a&gt;, but this isn’t the scope of this section). &lt;strong&gt;Although integration tests are helpful, that’s not always what we want to do. To give us more flexibility, we should decouple &lt;code class=&quot;highlighter-rouge&quot;&gt;CustomerService&lt;/code&gt; from the actual implementation, which can be done via an interface like so&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerStorer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Creates a storage abstraction&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;StoreCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;storer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerStorer&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Decouples CustomerService from the actual implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateNewCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;storer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StoreCustomer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Because storing a customer is now done via an interface, this gives us more flexibility in how we want to test the method&lt;/strong&gt;. For instance, we can:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use the concrete implementation via integration tests&lt;/li&gt;
  &lt;li&gt;Use a mock (or any kind of test double) via unit tests&lt;/li&gt;
  &lt;li&gt;Or both&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;restricting-behavior&quot;&gt;Restricting behavior&lt;/h4&gt;

&lt;p&gt;The last use case we will discuss can be pretty &lt;strong&gt;counterintuitive&lt;/strong&gt;(违反常理的) at first sight. It’s about restricting a type to a specific behavior. Let’s imagine we implement a custom configuration package to deal with dynamic configuration. We create a specific container for int configurations via an &lt;code class=&quot;highlighter-rouge&quot;&gt;IntConfig&lt;/code&gt; struct that also exposes two methods: &lt;code class=&quot;highlighter-rouge&quot;&gt;Get&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Set&lt;/code&gt;. Here’s how that code would look:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IntConfig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Retrieve configuration&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Update configuration&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, suppose we receive an &lt;code class=&quot;highlighter-rouge&quot;&gt;IntConfig&lt;/code&gt; that holds some specific configuration, such as a threshold. &lt;strong&gt;Yet, in our code, we are only interested in retrieving the configuration value, and we want to prevent updating it. How can we enforce that, semantically, this configuration is read-only, if we don’t want to change our configuration package?&lt;/strong&gt; By creating an abstraction that restricts the behavior to retrieving only a config value:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intConfigGetter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, in our code, we can rely on &lt;code class=&quot;highlighter-rouge&quot;&gt;intConfigGetter&lt;/code&gt; instead of the concrete implementation:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intConfigGetter&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewFoo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intConfigGetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Injects the configuration getter&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;threshold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Reads the configuration&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, the configuration getter is injected into the &lt;code class=&quot;highlighter-rouge&quot;&gt;NewFoo&lt;/code&gt; factory method. It doesn’t impact a client of this function because it can still pass an &lt;code class=&quot;highlighter-rouge&quot;&gt;IntConfig&lt;/code&gt; struct as it implements intConfigGetter. Then, we can only read the configuration in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Bar&lt;/code&gt; method, not modify it. Therefore, we can also use interfaces to restrict a type to a specific behavior for various reasons, such as semantics enforcement.&lt;/p&gt;

&lt;h3 id=&quot;interface-pollution&quot;&gt;Interface pollution&lt;/h3&gt;

&lt;p&gt;It’s fairly common to see interfaces being overused in Go projects. Perhaps the developer’s background was &lt;code class=&quot;highlighter-rouge&quot;&gt;C#&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;Java&lt;/code&gt;, and they found it natural to create interfaces before concrete types. However, this isn’t how things should work in &lt;code class=&quot;highlighter-rouge&quot;&gt;Go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As we discussed, interfaces are made to create abstractions. And the main &lt;strong&gt;caveat&lt;/strong&gt;(警告; 提醒) when programming meets abstractions is remembering that &lt;strong&gt;abstractions should be discovered, not created&lt;/strong&gt;. What does this mean? &lt;strong&gt;It means we shouldn’t start creating abstractions in our code if there is no immediate reason to do so. We shouldn’t design with interfaces but wait for a concrete need. Said differently, we should create an interface when we need it, not when we foresee that we could need it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes6.png&quot; alt=&quot;100_go_mistakes6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In summary, we should be cautious when creating abstractions in our code—abstractions should be discovered, not created. It’s common for us, software developers, to overengineer our code by trying to guess what the perfect level of abstraction is, based on what we think we might need later. This process should be avoided because, in most cases, it pollutes our code with unnecessary abstractions, making it more complex to read.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes7.png&quot; alt=&quot;100_go_mistakes7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s not try to solve a problem abstractly but solve what has to be solved now. Last, but not least, if it’s unclear how an interface makes the code better, we should probably consider removing it to make our code simpler.&lt;/p&gt;

&lt;h3 id=&quot;分析解释&quot;&gt;分析解释&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;核心定义与成因&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;接口污染的核心在于过度使用抽象。这通常发生在使用习惯了 C# 或 Java 等语言的开发者身上，他们习惯在编写具体类型之前先定义接口。在 Go 中，这种“预见性”的设计往往会导致代码中出现大量没有实际价值的间接层。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;为什么这是一个问题？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;增加复杂性&lt;/strong&gt;：无用的间接层会干扰代码流，使阅读、理解和推理代码变得更加困难。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;降低可读性&lt;/strong&gt;：如果接口的用途不明确，调用者往往需要花费更多精力去寻找真正的实现逻辑。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;性能开销&lt;/strong&gt;：虽然在许多场景下微不足道，但通过接口调用方法需要在运行时进行哈希表查找以定位具体类型，这会带来一定的性能损耗。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Go 的核心哲学：发现而非创造&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;来源强调了一个关键原则：&lt;strong&gt;抽象应该是被发现的，而不是被创造的（Abstractions should be discovered, not created）&lt;/strong&gt;。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;开发者不应该为了“预见”未来可能的需求而提前创建接口。&lt;/li&gt;
  &lt;li&gt;只有当接口能让代码变得更好（例如提高可重用性或简化测试）时，才应该引入它。&lt;/li&gt;
  &lt;li&gt;Rob Pike 曾指出：“不要针对接口设计，要发现接口”。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;什么时候不属于接口污染？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这些场景下接口能带来明确的价值：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;共同行为（Common behavior）&lt;/strong&gt;：当多个类型需要实现相同的逻辑（如标准库中的 &lt;code class=&quot;highlighter-rouge&quot;&gt;sort.Interface&lt;/code&gt; 或 &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt;）时，通过接口提取共性。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;解耦（Decoupling）&lt;/strong&gt;：为了让代码不依赖于具体的实现（例如数据库存储），从而方便进行单元测试（使用 &lt;code class=&quot;highlighter-rouge&quot;&gt;Mock&lt;/code&gt; 对象）或在未来更换实现方案。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;限制行为（Restricting behavior）&lt;/strong&gt;：通过接口强制实施语义约束，例如将一个具有读写能力的结构体限制为只读。&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;总结建议&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果你发现很难解释某个接口存在的理由，或者直接调用具体实现会让代码更简洁，那么这个接口很可能就是“污染”。&lt;strong&gt;在 Go 中，建议先编写具体的实现，等到实际需要解耦或处理多种类型时再提取接口&lt;/strong&gt;。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;比喻理解&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;接口就像是翻译官&lt;/strong&gt;。在只有两个说相同语言的人对话时，强制在中间塞进一个翻译官（接口）只会让沟通变慢且容易产生误解；只有当一个说中文的人需要和多个说不同外语的人（多种具体类型）交流，或者需要确保对话内容可以随时录音存档（测试解耦）时，翻译官的存在才有意义。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;接口就像是一份合同&lt;/strong&gt;。在生意还没开始做（没有实际业务逻辑）之前，就急着起草成百上千份细节详尽的合同（过度设计接口），只会让简单的买卖变得复杂无比。正确的做法是先开始交易（编写具体代码），当发现有多个合作伙伴都在做同样的事，或者需要规避某些风险时，再针对性地签一份简洁有效的合同（发现并提取接口）。&lt;/p&gt;

&lt;h2 id=&quot;6-interface-on-the-producer-side-生产者端接口&quot;&gt;6. Interface on the producer side (生产者端接口)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Keeping interfaces on the client side avoids unnecessary abstractions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interfaces are satisfied implicitly in Go, which tends to be a gamechanger compared to languages with an explicit implementation. In most cases, the approach to follow is similar to what we described in the previous section: &lt;strong&gt;abstractions should be discovered, not created&lt;/strong&gt;. This means that it’s not up to the producer to force a given abstraction for all the clients. Instead, it’s up to the client to decide whether it needs some form of abstraction and then determine the best abstraction level for its needs.&lt;/p&gt;

&lt;p&gt;An interface should live on the consumer side in most cases. However, in particular contexts (for example, when we know—not foresee—that an abstraction will be helpful for consumers), we may want to have it on the producer side. If we do, we should strive to keep it as minimal as possible, increasing its reusability potential and making it more easily composable.&lt;/p&gt;

&lt;p&gt;“&lt;strong&gt;生产者端接口&lt;/strong&gt;” 这一话题讨论的是：接口应该由谁定义？是&lt;strong&gt;实现方（生产者）&lt;/strong&gt;，还是&lt;strong&gt;使用方（消费者）&lt;/strong&gt;？Go 社区的最佳实践给出了明确答案：&lt;strong&gt;在绝大多数情况下，接口应该定义在使用方（消费者）的代码中&lt;/strong&gt;。这与很多面向对象语言（如 Java、C#）的惯用法截然不同，其根源在于 Go 接口的&lt;strong&gt;隐式满足&lt;/strong&gt;特性。&lt;/p&gt;

&lt;p&gt;生产者端定义接口的问题：&lt;/p&gt;

&lt;p&gt;如果生产者（例如一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;MySQLUserRepository&lt;/code&gt; 的实现包）自己定义了一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;IUserRepository&lt;/code&gt; 接口，然后让实现去满足它，这会导致：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;不必要的耦合&lt;/strong&gt;：生产者锁定了抽象层次，所有消费者都被迫使用这个可能包含他们不需要的方法的接口。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;僵化的设计&lt;/strong&gt;：接口难以演进，因为任何修改都可能破坏所有实现者和消费者。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;过度设计&lt;/strong&gt;：生产者容易设计出“大而全”的接口，因为它试图预测所有可能的用途。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;消费者端定义接口的优势：&lt;/p&gt;

&lt;p&gt;消费者（例如业务逻辑层）根据自己需要的方法来定义一个接口。&lt;/p&gt;

&lt;p&gt;示例：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 生产者包 (producer) - 提供具体实现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetUserByID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UpdateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeleteUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunComplexAnalytics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Report&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 某个复杂方法&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 消费者包 (consumer) - 定义自己所需的接口&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// UserSaver 是消费者为自己定义的接口，只包含它真正需要的方法&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserSaver&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CreateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessSignup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;saver&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserSaver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 这里只关心“保存”这个行为&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CreateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// UserGetter 是另一个消费者定义的接口，用于不同的场景&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserGetter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;GetUserByID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetUserProfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserGetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetUserByID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;优势：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;解耦与灵活&lt;/strong&gt;：消费者 &lt;code class=&quot;highlighter-rouge&quot;&gt;service&lt;/code&gt; 包完全不依赖生产者的具体类型（&lt;code class=&quot;highlighter-rouge&quot;&gt;MySQLUserRepository&lt;/code&gt;），只依赖自己定义的小接口。这符合依赖倒置原则。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;按需抽象&lt;/strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;：ProcessSignup&lt;/code&gt; 函数只需要一个能 &lt;code class=&quot;highlighter-rouge&quot;&gt;CreateUser&lt;/code&gt; 的东西，它就定义这样一个极简接口。这避免了依赖不需要的方法（如 &lt;code class=&quot;highlighter-rouge&quot;&gt;RunComplexAnalytics&lt;/code&gt;）。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;易于测试&lt;/strong&gt;：为 &lt;code class=&quot;highlighter-rouge&quot;&gt;UserSaver&lt;/code&gt; 或 &lt;code class=&quot;highlighter-rouge&quot;&gt;UserGetter&lt;/code&gt; 编写模拟测试非常容易。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;组合自由&lt;/strong&gt;：生产者 &lt;code class=&quot;highlighter-rouge&quot;&gt;db.MySQLUserRepository&lt;/code&gt; 隐式地满足了这些接口，无需任何声明。未来可以轻松换用其他存储（如 &lt;code class=&quot;highlighter-rouge&quot;&gt;PostgresUserRepository&lt;/code&gt;、&lt;code class=&quot;highlighter-rouge&quot;&gt;MockRepository&lt;/code&gt;），只要它们实现了相应的方法。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;何时放在生产者端？（例外情况）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;原则总有例外。在以下情况下，由生产者定义接口是合理的：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;提供通用、稳定的契约&lt;/strong&gt;：当你提供的不是一个具体实现，而是一个被广泛认可、极简且稳定的行为契约时。标准库中的 &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt;、&lt;code class=&quot;highlighter-rouge&quot;&gt;io.Writer&lt;/code&gt;、&lt;code class=&quot;highlighter-rouge&quot;&gt;error&lt;/code&gt; 接口就是典范。它们定义了计算机科学中的基础概念，几乎不会改变。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;在包内部隐藏实现细节&lt;/strong&gt;：在包内部使用接口来解耦具体实现，对外部消费者隐藏复杂结构。但这属于内部实现细节，对外暴露的通常仍是函数或结构体。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;提供可选功能&lt;/strong&gt;：例如 &lt;code class=&quot;highlighter-rouge&quot;&gt;sql.Driver&lt;/code&gt; 接口，它定义了数据库驱动必须实现的方法，这是一个框架级的、由生产者（&lt;code class=&quot;highlighter-rouge&quot;&gt;database/sql&lt;/code&gt; 包）定义的“插件”接口。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;关键点&lt;/strong&gt;：当你决定在生产者端定义接口时，务必遵循 “&lt;strong&gt;接口越小越好&lt;/strong&gt;” 的原则。一个只包含1-3个方法的接口，远比一个20个方法的“全能”接口更有用、更持久、更容易组合。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes8.png&quot; alt=&quot;100_go_mistakes8&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;7-returning-interfaces-返回接口&quot;&gt;7. Returning interfaces (返回接口)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;To prevent being restricted in terms of flexibility, a function shouldn’t return interfaces but concrete implementations in most cases. Conversely, a function should accept interfaces whenever possible&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In most cases, we shouldn’t return interfaces but concrete implementations. Otherwise, it can make our design more complex due to package dependencies and can restrict flexibility because all the clients would have to rely on the same abstraction. Again, the conclusion is similar to the previous sections: if we know (not foresee) that an abstraction will be helpful for clients, we can consider returning an interface. Otherwise, we shouldn’t force abstractions; they should be discovered by clients. If a client needs to abstract an implementation for whatever reason, it can still do that on the client’s side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;函数应该返回具体类型，而不是接口类型。但函数应该尽可能接受接口作为参数&lt;/strong&gt;。这个原则与”生产者端接口”的思想一脉相承，&lt;strong&gt;都是为了保持最大的灵活性和避免过早抽象&lt;/strong&gt;。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;这个原则的核心思想是：&lt;strong&gt;作为API提供者，不要替用户做决定。给他们具体的东西，让他们自己决定如何使用和抽象&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;为什么不应该返回接口？&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;问题1：限制灵活性&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;当函数返回接口时，你强制所有调用者都使用相同的抽象。这意味着：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 不推荐：返回接口&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserRepository&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UserRepository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 所有调用者都必须使用 UserRepository 接口&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// 即使他们可能有特殊需求&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;相比之下，返回具体类型：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ✅ 推荐：返回具体类型&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MySQLRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SpecialMySQLFeature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 具体类型的特有方法&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;优势：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;调用者可以选择直接使用具体类型的所有功能&lt;/li&gt;
  &lt;li&gt;调用者也可以选择仅使用接口（如果需要抽象）&lt;/li&gt;
  &lt;li&gt;不会强制所有调用者使用相同的抽象级别&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;问题2：依赖方向问题&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;返回接口可能导致不合理的包依赖关系：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 问题：返回接口导致消费者依赖生产者的抽象定义&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// producer.go (生产者包)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyInterface&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;DoSomething&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyInterface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;impl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// consumer.go (消费者包) - 必须导入 producer 包才能使用 MyInterface&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;producer&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;producer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 类型是 producer.MyInterface&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 现在 consumer 依赖 producer 的接口定义&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;问题3：违背”发现抽象”原则&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果生产者返回接口，等于预先决定了抽象。但根据之前的原则，抽象应该由消费者在需要时自己发现和定义。&lt;/p&gt;

&lt;p&gt;为什么应该接受接口作为参数？-&amp;gt; &lt;strong&gt;提高通用性和可测试性&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ✅ 优秀实践：接受接口，返回具体类型&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 接受接口 - 提高函数通用性&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 可以接受文件、网络连接、内存缓冲区等&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 返回具体类型 - 给予调用者选择权&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewProcessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConcreteProcessor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConcreteProcessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;何时可以返回接口？-&amp;gt; 在明确知道（而非预见）返回接口会带来实际好处的情况下&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;场景1：提供可选行为的场景&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 标准库的 error 接口是一个很好的例子&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// error 是一个极简接口，有明确的契约&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 返回 error 接口是合理的，因为它定义了一个基本行为&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 可能返回各种具体的 error 类型&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ParseError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;场景2：工厂模式或策略模式&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 当函数的作用是创建某种策略的实现时&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 根据配置返回不同的日志实现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;console&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsoleLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DefaultLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;场景3：隐藏内部复杂的实现细节&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 当你不想暴露实现细节时&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Cache&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// New 返回接口，隐藏了具体是哪种缓存实现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Cache&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 可能使用 Redis、内存或其他&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createComplexCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;8-any-says-nothing-滥用-any-类型&quot;&gt;8. any says nothing (滥用 any 类型)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Only use &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt; if you need to accept or return any possible type, such as &lt;code class=&quot;highlighter-rouge&quot;&gt;json.Marshal&lt;/code&gt;. Otherwise, any doesn’t provide meaningful information and can lead to compile-time issues by allowing a caller to call methods with any data type.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt; type can be helpful if there is a genuine need for accepting or returning any possible type (for instance, when it comes to marshaling or formatting). In general, we should avoid overgeneralizing the code we write at all costs. Perhaps a little bit of duplicated code might occasionally be better if it improves other aspects such as code expressiveness.&lt;/p&gt;

&lt;p&gt;仅在真正需要接受或返回任意可能类型时才使用 any（例如 json.Marshal）。否则，any 不会提供有意义的信息，并可能因为允许调用者用任何数据类型调用方法而导致编译时问题。&lt;/p&gt;

&lt;p&gt;在 &lt;code class=&quot;highlighter-rouge&quot;&gt;Go 1.18+&lt;/code&gt; 中，any 是空接口 &lt;code class=&quot;highlighter-rouge&quot;&gt;interface{}&lt;/code&gt; 的类型别名：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这意味着 &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt; 可以容纳任何类型的值，但这恰恰是它最大的危险所在。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;关键要点：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;any 意味着”没有任何类型信息”：使用它时，你放弃了编译时的类型检查&lt;/li&gt;
  &lt;li&gt;错误从编译时推迟到运行时：这违背了静态类型语言的优势&lt;/li&gt;
  &lt;li&gt;代码可读性下降：读者不知道函数接受什么类型的参数&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;优先选择其他方案：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;具体类型（最明确）&lt;/li&gt;
  &lt;li&gt;接口（定义行为）&lt;/li&gt;
  &lt;li&gt;泛型（类型安全的抽象）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;记住：少量的重复代码（如为不同类型写相似函数）通常比过度抽象的、使用 any 的代码更好，因为前者更清晰、更安全、更易维护。只有当真正需要处理任意类型时（如序列化、格式化等），才应使用 any。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;为什么滥用-any-有害&quot;&gt;为什么滥用 &lt;code class=&quot;highlighter-rouge&quot;&gt;any&lt;/code&gt; 有害？&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;失去类型安全性（最严重的问题）&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 危险的示例&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 为了使用 data，我们需要类型断言&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 但这在编译时无法检查&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 如果 data 不是 string，运行时会 panic！&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c&quot;&gt;// 正常&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;c&quot;&gt;// 编译通过，但运行时会 panic！&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 编译通过，但运行时会 panic！&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;代码意图不清晰&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 不清晰：这个函数到底接受什么？&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 什么类型的 value 是合法的？&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ✅ 清晰：明确说明接受什么&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StoreString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StoreInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StoreUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;推迟错误到运行时&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;类型错误应该在编译时捕获，而不是运行时：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 错误在运行时才发现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 假设是 int，但不保证&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 编译通过，但...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c&quot;&gt;// 正常：返回 30&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;20&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;// 编译通过，但运行时会 panic！&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;10&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;// 编译通过，但运行时会 panic！&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ✅ 更好的方式：使用泛型（Go 1.18+）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Calculate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 类型安全，编译时检查&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;何时应该使用-any&quot;&gt;何时应该使用 any？&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;处理未知结构的 JSON 数据&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 这是合理的，因为 JSON 可以是任何结构&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ParseJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;容器数据结构&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 当实现通用容器时（尽管泛型通常是更好的选择）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 但更好的做法是使用泛型：&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;格式化和日志&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// fmt 包正确使用 any&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 日志记录通常接受 any&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;User %v logged in at %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;标准库中的合理使用&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// encoding/json&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Marshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// fmt&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// context&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;使用-any-的安全模式&quot;&gt;使用 any 的安全模式&lt;/h3&gt;

&lt;p&gt;如果必须使用 any，请遵循这些安全模式：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;立即进行类型检查&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SafeProcess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;unsupported type: %T&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;使用类型断言的安全形式&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 安全断言，不会 panic&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;someValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// 安全地使用 str&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// 处理类型不匹配&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;约束 any 的使用范围&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 内部使用 any，但对外暴露类型安全的接口&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processInternal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 内部处理，假设调用者知道规则&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 公开的类型安全方法&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processInternal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processInternal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;替代方案使用泛型go-118&quot;&gt;替代方案：使用泛型（Go 1.18+）&lt;/h3&gt;

&lt;p&gt;大多数滥用 any 的场景都可以用泛型更好地解决：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 使用 any&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FindInSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 比较可能不如预期&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ✅ 使用泛型&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FindInSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slice&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 类型安全的比较&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 使用&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FindInSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 正确&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FindInSlice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;c&quot;&gt;// 正确&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// FindInSlice([]string{&quot;a&quot;, &quot;b&quot;}, 123)    // 编译错误：类型不匹配&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;9-being-confused-about-when-to-use-generics-泛型使用不当&quot;&gt;9. Being confused about when to use generics (泛型使用不当)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Relying on generics and type parameters can prevent writing boilerplate code to factor out elements or behaviors. However, do not use type parameters prematurely, but only when you see a concrete need for them. Otherwise, they introduce unnecessary abstractions and complexity.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More: &lt;a href=&quot;https://100go.co/9-generics/&quot;&gt;Being confused about when to use generics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;核心观点：依赖泛型和类型参数可以避免编写提取元素或行为的样板代码。但是，不要过早使用类型参数，只有在看到具体需要时才使用它们。否则，它们会引入不必要的抽象和复杂性。&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;sort&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;unknown type: %T&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeysGenerics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customConstraint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getKeysWithConstraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customConstraint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Val&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Compare&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Less&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Compare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SliceFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Compare&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;10-not-being-aware-of-the-possible-problems-with-type-embedding-类型嵌入风险&quot;&gt;10. Not being aware of the possible problems with type embedding (类型嵌入风险)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Using type embedding can also help avoid boilerplate code; however, ensure that doing so doesn’t lead to visibility issues where some fields should have remained hidden&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;核心观点：使用类型嵌入可以帮助避免样板代码，但要确保这样做不会导致可见性问题，即某些本应保持隐藏的字段被意外暴露。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When creating a struct, Go offers the option to embed types. But this can sometimes lead to unexpected behaviors if we don’t understand all the implications of type embedding. Throughout this section, we look at how to embed types, what these bring, and the possible issues.&lt;/p&gt;

&lt;p&gt;In Go, a struct field is called embedded if it’s declared without a name. For example,&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// Embedded field&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt; struct, the &lt;code class=&quot;highlighter-rouge&quot;&gt;Bar&lt;/code&gt; type is declared without an associated name; hence, &lt;strong&gt;it’s an embedded field&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We use embedding to promote the fields and methods of an embedded type. Because &lt;code class=&quot;highlighter-rouge&quot;&gt;Bar&lt;/code&gt; contains a &lt;code class=&quot;highlighter-rouge&quot;&gt;Baz&lt;/code&gt; field, this field is promoted to &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt;. Therefore, &lt;code class=&quot;highlighter-rouge&quot;&gt;Baz&lt;/code&gt; becomes available from &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What can we say about type embedding? First, let’s note that it’s rarely a necessity, and it means that whatever the use case, we can probably solve it as well without type embedding. Type embedding is mainly used for convenience: in most cases, to promote behaviors.&lt;/p&gt;

&lt;p&gt;If we decide to use type embedding, we need to keep two main constraints in mind:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It shouldn’t be used solely as some syntactic sugar to simplify accessing a field (such as &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo.Baz()&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo.Bar.Baz()&lt;/code&gt;). If this is the only rationale, let’s not embed the inner type and use a field instead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It shouldn’t promote data (fields) or a behavior (methods) we want to hide from the outside: for example, if it allows clients to access a locking behavior that should remain private to the struct.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using type embedding consciously by keeping these constraints in mind can help avoid boilerplate code with additional forwarding methods. However, let’s make sure we don’t do it solely for cosmetics and not promote elements that should remain hidden.&lt;/p&gt;

&lt;p&gt;示例代码：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;io&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;sync&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fooBar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InMem&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mutex&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InMem&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InMem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;writeCloser&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WriteCloser&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writeCloser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writeCloser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writeCloser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;什么是类型嵌入？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;类型嵌入是 Go 中结构体字段的一种特殊声明方式，&lt;strong&gt;字段没有名称，只有类型&lt;/strong&gt;：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入字段，没有字段名，只有类型&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt; 结构体中，&lt;code class=&quot;highlighter-rouge&quot;&gt;Bar&lt;/code&gt; 类型被嵌入，因此 &lt;code class=&quot;highlighter-rouge&quot;&gt;Bar&lt;/code&gt; 的字段和方法会被”提升”到 &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt; 中，可以直接通过 &lt;code class=&quot;highlighter-rouge&quot;&gt;Foo&lt;/code&gt; 访问。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;类型嵌入的主要用途&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;(1) 方法提升：嵌入类型的方法会被提升到外层类型，可以避免编写转发方法&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入，File 现在有了 Read 方法&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 无需编写转发方法：&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// func (f File) Read(p []byte) (n int, err error) {&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//     return f.File.Read(p)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(2) 接口实现：通过嵌入，外层类型自动实现了内层类型实现的接口&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyReader&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入，MyReader 自动实现了 io.Reader 接口&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;类型嵌入的潜在问题&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;(1) 意外暴露私有字段和方法&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 问题示例：意外暴露内部实现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Account&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mutex&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入锁&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;balance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// ⚠️ 问题：外部可以直接调用锁的方法&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 这破坏了封装性&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;问题：&lt;code class=&quot;highlighter-rouge&quot;&gt;sync.Mutex&lt;/code&gt; 的 &lt;code class=&quot;highlighter-rouge&quot;&gt;Lock()&lt;/code&gt; 和 &lt;code class=&quot;highlighter-rouge&quot;&gt;Unlock()&lt;/code&gt; 方法被提升到 &lt;code class=&quot;highlighter-rouge&quot;&gt;Account&lt;/code&gt;，&lt;strong&gt;外部代码可以直接控制锁&lt;/strong&gt;，可能导致：死锁风险，锁状态管理混乱，破坏了数据封装的完整性。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(2) 命名冲突和歧义&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A.Process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;B.Process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// c.Process()  // ⚠️ 编译错误：ambiguous selector c.Process&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 必须明确指定：&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 正确&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 正确&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(3) 接口实现冲突&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FileWriter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入接口&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 问题：FileWriter 没有实现 Write 方法&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// 但在编译时不会报错，直到运行时才可能发现&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(4) 过度提升导致 API 污染&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 嵌入过多的类型可能导致 API 过于复杂&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;DatabaseConfig&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CacheConfig&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;APIConfig&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LoggingConfig&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 所有嵌入类型的公共方法都会被提升&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 使用 Config 时，会有大量方法可用，但很多可能是不相关的&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;使用类型嵌入的最佳实践&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;(1) 仅在需要行为提升时使用&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ✅ 正确：需要提升 io.Reader 的行为&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入，为了获得 Read 方法&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ❌ 错误：仅仅为了语法糖&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Address&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入，只是为了能写 user.City 而不是 user.Address.City&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ✅ 更好：使用命名字段&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Address&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 命名字段，访问需要 user.addr.City&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(2) 不要嵌入应该隐藏的类型&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 错误：暴露内部同步机制&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SafeCounter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mutex&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ✅ 正确：将锁作为私有字段&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SafeCounter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mutex&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 私有字段，不暴露 Mutex 的方法&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SafeCounter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Increment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(3) 优先组合而非继承思维&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Go 鼓励组合而非继承&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 明确组合各个组件&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;httpServer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mux&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Router&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 而不是：&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入可能导致不必要的方法提升&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mux&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Router&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(4) 谨慎处理接口嵌入&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ✅ 正确使用接口嵌入&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ReadWriter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reader&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 小心：确保类型确实实现了接口&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyType&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 嵌入接口&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewMyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Writer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 确保传入的 w 不为 nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;记住：类型嵌入是工具，不是必需品。在 Go 中，几乎总能通过不使用类型嵌入来解决问题。只有当它真正简化了代码且不会导致可见性问题时，才应该使用它。&lt;/p&gt;

&lt;h2 id=&quot;11-not-using-the-functional-options-pattern-缺少函数选项模式&quot;&gt;11. Not using the functional options pattern (缺少函数选项模式)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;To handle options conveniently and in an API-friendly manner, use the functional options pattern.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;核心观点：为了以方便且 API 友好的方式处理选项，请使用函数选项模式。这是一种优雅处理可选参数和配置的方法。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Although there are different implementations with minor variations, the main idea is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An unexported struct holds the configuration: options.&lt;/li&gt;
  &lt;li&gt;Each option is a function that returns the same type: &lt;code class=&quot;highlighter-rouge&quot;&gt;type Option func(options *options) error&lt;/code&gt;. For example, &lt;code class=&quot;highlighter-rouge&quot;&gt;WithPort&lt;/code&gt; accepts an &lt;code class=&quot;highlighter-rouge&quot;&gt;int&lt;/code&gt; argument that represents the port and returns an &lt;code class=&quot;highlighter-rouge&quot;&gt;Option&lt;/code&gt; type that represents how to update the &lt;code class=&quot;highlighter-rouge&quot;&gt;options&lt;/code&gt; struct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes10.png&quot; alt=&quot;100_go_mistakes10&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;port should be positive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// At this stage, the options struct is built and contains the config&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// Therefore, we can implement our logic related to port configuration&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultHTTPPort&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;randomPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The functional options pattern provides a handy and API-friendly way to handle options. Although the builder pattern can be a valid option, it has some minor downsides (having to pass a config struct that can be empty or a less handy way to handle error management) that tend to make the functional options pattern the idiomatic way to deal with these kind of problems in Go.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;为什么需要函数选项模式？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 Go 中，函数通常有多个配置选项，传统的解决方法有以下问题：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(1) 配置结构体问题&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 问题：需要传入完整配置结构体，即使很多字段是默认值&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// ... 更多字段&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 即使只需要设置 Port，也要创建完整 Config&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 使用：&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:8080&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 必须指定默认值&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;               &lt;span class=&quot;c&quot;&gt;// 必须明确传递 nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(2) 多参数问题&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 问题：参数太多，难以记忆和维护&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxConns&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tlsConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 参数顺序重要，且必须传递所有参数&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;(3) 变长参数使用基础类型&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ❌ 问题：类型不安全，可读性差&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 需要类型断言，容易出错&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;函数选项模式解决方案&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;基本结构&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 1. 非导出配置结构体&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;maxConns&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 2. Option 函数类型&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 3. 选项构造函数（通常以 With 开头）&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;65535&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;invalid port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;timeout must be positive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;logger cannot be nil&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 4. 构造函数使用可变参数接受选项&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 设置默认值&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;           &lt;span class=&quot;c&quot;&gt;// 使用指针表示可选&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;defaultLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;maxConns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 应用所有选项&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;applying option: %w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 最终配置处理&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultPort&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 创建并返回 Server&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;使用示例&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 只设置需要的选项，顺序无关&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;server1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;server2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WithPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WithTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;server3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WithLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;customLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WithPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;函数选项模式是 Go 社区广泛接受的配置模式，特别是在标准库和流行开源项目中常见。它提供了优秀的 API 体验，同时保持了代码的简洁和可维护性。&lt;/p&gt;

&lt;h2 id=&quot;12-project-misorganization-project-structure-and-package-organization-项目结构与包名管理&quot;&gt;12. Project misorganization (project structure and package organization) (项目结构与包名管理)&lt;/h2&gt;

&lt;p&gt;Regarding the overall organization, there are different schools of thought. For example, should we organize our application by context or by layer? It depends on our preferences. We may favor grouping code per context (such as the customer context, the contract context, etc.), or we may favor following hexagonal(六边形的) architecture principles and group per technical layer. If the decision we make fits our use case, it cannot be a wrong decision, as long as we remain consistent with it.&lt;/p&gt;

&lt;p&gt;Regarding packages, there are multiple best practices that we should follow. First, we should avoid premature packaging because it might cause us to overcomplicate a project. Sometimes, it’s better to use a simple organization and have our project evolve when we understand what it contains rather than forcing ourselves to make the perfect structure up front. Granularity is another essential thing to consider. We should avoid having dozens of nano packages containing only one or two files. If we do, it’s because we have probably missed some logical connections across these packages, making our project harder for readers to understand. Conversely, we should also avoid huge packages that dilute the meaning of a package name.&lt;/p&gt;

&lt;p&gt;Package naming should also be considered with care. As we all know (as developers), naming is hard. To help clients understand a Go project, we should name our packages after what they provide, not what they contain. Also, naming should be meaningful. Therefore, a package name should be short, concise, expressive, and, by convention, a single lowercase word.&lt;/p&gt;

&lt;p&gt;Regarding what to export, the rule is pretty straightforward. We should minimize what should be exported as much as possible to reduce the coupling between packages and keep unnecessary exported elements hidden. If we are unsure whether to export an element or not, we should default to not exporting it. Later, if we discover that we need to export it, we can adjust our code. Let’s also keep in mind some exceptions, such as making fields exported so that a struct can be unmarshaled with encoding/json.&lt;/p&gt;

&lt;p&gt;Organizing a project isn’t straightforward, but following these rules should help make it easier to maintain. However, remember that consistency is also vital to ease maintainability. Therefore, let’s make sure that we keep things as consistent as possible within a codebase.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: In 2023, the Go team has published an official guideline for organizing / structuring a Go project: go.dev/doc/modules/layout&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;核心观点：项目组织没有单一标准答案，但遵循一些最佳实践可以使代码更易维护。关键在于保持一致性，选择适合团队和项目的方式。&lt;/p&gt;

&lt;h3 id=&quot;项目结构组织方式&quot;&gt;项目结构组织方式&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;按业务上下文组织 vs 按技术层组织&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;建议：没有绝对正确，选择后保持一致性。Go社区倾向于按业务上下文组织。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;按业务上下文（领域驱动）&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project/
  customer/          # 客户上下文
    handler.go
    service.go
    repository.go
    model.go
  order/             # 订单上下文
    handler.go
    service.go
    repository.go
    model.go
  product/           # 产品上下文
    handler.go
    service.go
    repository.go
    model.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;高内聚：相关业务逻辑集中在一起&lt;/li&gt;
  &lt;li&gt;易于维护：修改某个功能时只需关注单个目录&lt;/li&gt;
  &lt;li&gt;符合微服务趋势：便于未来拆分为独立服务&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;按技术层（分层架构）&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project/
  handlers/          # 控制层
    customer_handler.go
    order_handler.go
    product_handler.go
  services/          # 业务逻辑层
    customer_service.go
    order_service.go
    product_service.go
  repositories/      # 数据访问层
    customer_repo.go
    order_repo.go
    product_repo.go
  models/            # 数据模型
    customer.go
    order.go
    product.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;关注点分离：每层有明确职责&lt;/li&gt;
  &lt;li&gt;技术栈统一：同类技术放在一起&lt;/li&gt;
  &lt;li&gt;传统模式：许多团队熟悉此模式&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;包组织最佳实践&quot;&gt;包组织最佳实践&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;(1) 避免过早分包&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;原则：让项目自然演进，不要一开始就设计复杂结构。&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 初期：从简单开始
project/
  main.go          # 包含所有逻辑
  utils.go         # 辅助函数

// 中期：按需拆分
project/
  cmd/
    server/
      main.go      # 入口
  internal/
    api/           # API相关
    db/            # 数据库操作
    models/        # 数据模型

// 成熟期：精细组织
project/
  cmd/
    server/
      main.go
  internal/
    user/          # 用户模块
    order/         # 订单模块
    product/       # 产品模块
  pkg/
    utils/         # 可复用的工具
    config/        # 配置管理
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(2) 包的粒度要适中&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// ❌ 过于细粒度（纳米包）
project/
  pkg/
    stringutil/    # 仅包含2-3个字符串函数
    intutil/       # 仅包含2-3个整数函数
    timeutil/      # 仅包含2-3个时间函数

// ❌ 过于粗粒度（巨型包）
project/
  pkg/
    utils/         # 包含数百个不相关的函数
                   # 名称失去意义

// ✅ 适度粒度
project/
  pkg/
    strutil/       # 字符串相关工具
    mathutil/      # 数学计算工具
    timeutil/      # 时间日期工具（包含相关功能）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(3) 包命名要明确&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// ❌ 糟糕的命名
common/         # 太泛，不知道提供什么
util/           # 不知道具体用途
helper/         # 不清楚帮助什么
misc/           # 杂物堆

// ✅ 好的命名
validator/      # 提供验证功能
formatter/      # 提供格式化功能
authenticator/  # 提供认证功能
cache/          # 提供缓存功能

// 规则：
// 1. 使用单数名词：user 而不是 users
// 2. 简短但描述性：log 而不是 loggingfacility
// 3. 避免缩写：strconv（允许） vs stcv（避免）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(4) 最小化导出&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;导出原则：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;默认不导出，需要时再公开&lt;/li&gt;
  &lt;li&gt;只导出必要的接口和函数&lt;/li&gt;
  &lt;li&gt;内部实现保持私有&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 内部包结构&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 导出必须的接口&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Cache&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 不导出具体实现&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redisCache&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 导出工厂函数&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewRedisCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redisCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connectRedis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 不导出的辅助函数&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connectRedis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 内部实现细节&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(5) 处理 JSON 序列化等特殊情况&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 字段必须导出才能被 encoding/json 访问&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;    &lt;span class=&quot;s&quot;&gt;`json:&quot;id&quot;`&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;email,omitempty&quot;`&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 不导出的字段不会被序列化&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;passwordHash&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;项目结构模板示例&quot;&gt;项目结构模板示例&lt;/h3&gt;

&lt;h4 id=&quot;标准-go-项目布局参考&quot;&gt;标准 Go 项目布局（参考）&lt;/h4&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;myproject/
├── cmd/                  # 可执行程序入口
│   ├── myapp/
│   │   └── main.go       # 主程序
│   └── mytool/
│       └── main.go       # 工具程序
├── internal/             # 私有应用代码
│   ├── api/              # API 层
│   ├── service/          # 业务逻辑层
│   ├── repository/       # 数据访问层
│   └── model/            # 数据模型
├── pkg/                  # 可公开导入的库代码
│   ├── libfoo/           # 库包 A
│   └── libbar/           # 库包 B
├── api/                  # API 定义（protobuf, OpenAPI）
├── web/                  # Web 资源
├── configs/              # 配置文件
├── init/                 # 初始化脚本
├── scripts/              # 构建/部署脚本
├── build/                # 构建输出
├── deployments/          # 部署配置
├── test/                 # 测试数据
├── docs/                 # 文档
├── tools/                # 开发工具
├── examples/             # 示例代码
├── vendor/               # 依赖（可选）
├── go.mod
├── go.sum
└── README.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;微服务项目结构&quot;&gt;微服务项目结构&lt;/h4&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;microservice/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── handler/          # HTTP/gRPC 处理器
│   ├── service/          # 业务逻辑实现
│   ├── repository/       # 数据持久化
│   ├── domain/           # 领域模型
│   ├── middleware/       # 中间件
│   └── config/           # 配置读取
├── pkg/
│   ├── logger/           # 日志组件
│   ├── database/         # 数据库封装
│   └── validator/        # 验证器
├── api/
│   └── v1/               # API 协议定义
├── deployments/
│   ├── docker/
│   └── kubernetes/
├── migrations/           # 数据库迁移
├── scripts/              # 脚本
└── tests/                # 测试
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;关键实践总结&quot;&gt;关键实践总结&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Do’s（应该做的）&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;从简单开始：开始时用扁平结构，需要时再重构&lt;/li&gt;
  &lt;li&gt;保持一致性：选定模式后，整个项目保持一致&lt;/li&gt;
  &lt;li&gt;合理命名：包名描述功能，而不是内容&lt;/li&gt;
  &lt;li&gt;最小化公开 API：只导出必要的部分&lt;/li&gt;
  &lt;li&gt;考虑可读性：让新成员能快速理解结构&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Don’ts（不应该做的）&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;不要过度设计：避免过早优化项目结构&lt;/li&gt;
  &lt;li&gt;不要创建太多小包：避免”纳米包”综合症&lt;/li&gt;
  &lt;li&gt;不要使用无意义的包名：如 &lt;code class=&quot;highlighter-rouge&quot;&gt;common&lt;/code&gt;、&lt;code class=&quot;highlighter-rouge&quot;&gt;utils&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;不要随意导出：默认私有，需要时再公开&lt;/li&gt;
  &lt;li&gt;不要忽略团队约定：遵循团队已有的模式&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;决策指南&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;当不确定如何组织时，问这些问题：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;项目规模：小型项目用简单结构，大型项目需要更细致的组织&lt;/li&gt;
  &lt;li&gt;团队规模：大团队需要更规范的结构，小团队可以更灵活&lt;/li&gt;
  &lt;li&gt;部署方式：单体应用 vs 微服务影响结构选择&lt;/li&gt;
  &lt;li&gt;维护周期：长期维护的项目需要更稳健的结构&lt;/li&gt;
  &lt;li&gt;外部依赖：是否作为库供他人使用？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;最后记住：没有完美的结构，只有适合当前项目的结构。随着项目演进，结构也需要调整。重要的是保持代码清晰、可维护，并让团队成员都能理解和遵循。&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;13-creating-utility-packages-避免使用通用无意义的包名&quot;&gt;13. Creating utility packages (避免使用通用、无意义的包名)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Naming is a critical piece of application design. Creating packages such as common, util, and shared doesn’t bring much value for the reader. Refactor such packages into meaningful and specific package names&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, bear in mind that naming a package after what it provides and not what it contains can be an efficient way to increase its expressiveness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;核心观点：避免使用通用、无意义的包名（如 &lt;code class=&quot;highlighter-rouge&quot;&gt;common&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;util&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;shared&lt;/code&gt;），而应使用具体、有意义的名称。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;这条建议的本质是：通过有目的性的包命名来驱动更好的软件设计。它强迫你思考每个类的单一职责和逻辑归属，从而产生更模块化、更易于理解和更健壮的代码结构。拒绝“杂物抽屉”，拥抱“精心整理的工具箱”。&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;为什么 util、common 这类包名不好？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;成为“杂物抽屉”
    &lt;ul&gt;
      &lt;li&gt;像 &lt;code class=&quot;highlighter-rouge&quot;&gt;utils&lt;/code&gt; 或 &lt;code class=&quot;highlighter-rouge&quot;&gt;common&lt;/code&gt; 这样的包，很容易变成一个什么都可以往里扔的“万能包”。随着项目增长，它会包含各种不相关的类：日期处理、字符串工具、加密助手、日志格式化、DTO 对象等等。&lt;/li&gt;
      &lt;li&gt;这违反了高内聚、低耦合的原则。包内的类之间几乎没有逻辑关联。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;对读者毫无价值
    &lt;ul&gt;
      &lt;li&gt;当你看到一个导入语句是 &lt;code class=&quot;highlighter-rouge&quot;&gt;from com.example.util import StringHelper&lt;/code&gt; 时，&lt;code class=&quot;highlighter-rouge&quot;&gt;util&lt;/code&gt; 这个词没有传达任何关于 &lt;code class=&quot;highlighter-rouge&quot;&gt;StringHelper&lt;/code&gt; 功能、所属领域或依赖关系的有效信息。&lt;/li&gt;
      &lt;li&gt;开发者必须深入查看代码才能理解这个类的用途和上下文。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;隐藏设计缺陷
    &lt;ul&gt;
      &lt;li&gt;将一些类随意放入 &lt;code class=&quot;highlighter-rouge&quot;&gt;util&lt;/code&gt;，可能会掩盖它们在领域模型中的正确位置。例如，一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;OrderValidator&lt;/code&gt; 本应属于 &lt;code class=&quot;highlighter-rouge&quot;&gt;order&lt;/code&gt; 领域包，却被错误地放入了 &lt;code class=&quot;highlighter-rouge&quot;&gt;common.validation&lt;/code&gt; 中，割裂了其与业务逻辑的联系。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;解决方案：创建有意义的包&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;原则是：以包“提供什么”或“属于哪个领域”来命名，而不是以它“包含什么杂项”来命名。&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;按功能/提供的能力分组&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;将“杂物抽屉”拆分成多个目的明确的小包。&lt;/p&gt;

&lt;p&gt;反面例子：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;com.company.util -&amp;gt; 包含 DateUtil, FileUtil, HttpUtil, EncryptionUtil
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;正面重构：这样，从包名就能立刻知道其核心职责&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;com.company.**time**.DateParser (专注于时间相关)

com.company.**io**.FileReader (专注于输入输出)

com.company.**http**.client.HttpClient (专注于HTTP通信)

com.company.**security**.encryption.Encryptor (专注于安全)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;按领域/模块分组&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;将工具类划分到它们所服务的特定业务领域或模块中。&lt;/p&gt;

&lt;p&gt;反面例子：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;com.company.common -&amp;gt; 包含 OrderHelper, UserDto, ConfigConstants
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;正面重构：这强化了领域边界，让代码与业务结构对齐&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;com.company.**order**.domain.OrderIdGenerator (属于order领域)

com.company.**user**.dto.UserResponse (属于user领域)

com.company.**configuration**.AppConfig (属于配置领域)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;平衡与例外&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;当然，在非常小的项目或原型中，一个 &lt;code class=&quot;highlighter-rouge&quot;&gt;utils&lt;/code&gt; 包可能无可厚非。但一旦项目开始增长，遵循这一原则将极大地提升代码的可读性、可维护性和架构清晰度。&lt;/p&gt;

&lt;h2 id=&quot;14-ignoring-package-name-collisions-变量名与包名发生冲突&quot;&gt;14. Ignoring package name collisions (变量名与包名发生冲突)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;To avoid naming collisions between variables and packages, leading to confusion or perhaps even bugs, use unique names for each one. If this isn’t feasible, use an import alias to change the qualifier to differentiate the package name from the variable name, or think of a better name.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Package collisions occur when a variable name collides with an existing package name, preventing the package from being reused. We should prevent variable name collisions to avoid ambiguity. If we face a collision, we should either find another meaningful name or use an import alias.&lt;/p&gt;

&lt;p&gt;核心问题：在 Go 中，当变量名、函数名或其他标识符与包名发生冲突时，会导致编译错误或混淆。特别是在使用包别名时，需要特别注意命名冲突。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;包导入与局部变量冲突&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 问题：变量名与包名相同&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;some string&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 这会覆盖 fmt 包的作用域&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 编译错误：fmt.Println 未定义（现在 fmt 是字符串）&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;多包同名冲突&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;github.com/user/config&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 第三方 config 包&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;myproject/config&quot;&lt;/span&gt;        &lt;span class=&quot;c&quot;&gt;// 本地 config 包 - 冲突！&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 两个包都叫 config，无法同时导入&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;包别名与标识符冲突&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;encoding/json&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 包别名&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;some data&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 变量名与包别名冲突&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 现在无法使用 json 包&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;解决方案：使用包别名&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;myConfig&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;github.com/user/config&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 为第三方包设置别名&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;localConfig&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;myproject/config&quot;&lt;/span&gt;     &lt;span class=&quot;c&quot;&gt;// 为本地包设置别名&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;formatted string&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;// 局部变量&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// 使用别名访问包&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;localCfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 Go 中处理包名冲突，优先使用有意义的包别名，其次考虑重命名局部标识符。Go 的静态类型系统和严格的导入规则使得提前发现和解决命名冲突变得更加重要。遵循”显式优于隐式”的原则，使用清晰的别名可以显著提高代码的可读性和可维护性。&lt;/p&gt;

&lt;h2 id=&quot;15-missing-code-documentation-缺少代码文档&quot;&gt;15. Missing code documentation (缺少代码文档)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;To help clients and maintainers understand your code’s purpose, document exported elements.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Documentation is an important aspect of coding. It simplifies how clients can consume an API but can also help in maintaining a project. In Go, we should follow some rules to make our code idiomatic:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, every exported element must be documented&lt;/strong&gt;. Whether it is a structure, an interface, a function, or something else, if it’s exported, it must be documented. The convention is to add comments, starting with the name of the exported element.&lt;/p&gt;

&lt;p&gt;As a convention, each comment should be a complete sentence that ends with punctuation. Also bear in mind that when we document a function (or a method), we should highlight what the function intends to do, not how it does it; this belongs to the core of a function and comments, not documentation. Furthermore, the documentation should ideally provide enough information that the consumer does not have to look at our code to understand how to use an exported element.&lt;/p&gt;

&lt;p&gt;When it comes to documenting a variable or a constant, we might be interested in conveying two aspects: its purpose and its content. The former should live as code documentation to be useful for external clients. The latter, though, shouldn’t necessarily be public.&lt;/p&gt;

&lt;p&gt;To help clients and maintainers understand a package’s scope, we should also document each package. The convention is to start the comment with &lt;code class=&quot;highlighter-rouge&quot;&gt;// Package&lt;/code&gt; followed by the package name. The first line of a package comment should be concise. That’s because it will appear in the package. Then, we can provide all the information we need in the following lines.&lt;/p&gt;

&lt;p&gt;Documenting our code shouldn’t be a constraint. We should take the opportunity to make sure it helps clients and maintainers to understand the purpose of our code.&lt;/p&gt;

&lt;p&gt;核心原则：&lt;strong&gt;所有导出的元素都必须有文档&lt;/strong&gt;。Go 语言通过文档注释（&lt;strong&gt;doc comments&lt;/strong&gt;）来生成官方文档，这是 Go 生态系统的核心组成部分。&lt;/p&gt;

&lt;h3 id=&quot;必须文档化的内容&quot;&gt;必须文档化的内容&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;(1) 包级文档（Package Documentation）&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;每个包都&lt;strong&gt;必须有&lt;/strong&gt;包级文档，通常放在包声明的上方：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Package httputil provides HTTP utility functions, complementing the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// more common ones in the net/http package.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// This package includes:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// - Request/response debugging helpers&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// - HTTP client utilities&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// - Common middleware components&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httputil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;规范要求：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;第一行以 &lt;code class=&quot;highlighter-rouge&quot;&gt;Package &amp;lt;包名&amp;gt;&lt;/code&gt; 开头&lt;/li&gt;
  &lt;li&gt;第一行简洁描述包的核心功能&lt;/li&gt;
  &lt;li&gt;后续行提供更详细的信息&lt;/li&gt;
  &lt;li&gt;显示在 &lt;code class=&quot;highlighter-rouge&quot;&gt;go doc&lt;/code&gt; 和 &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg.go.dev&lt;/code&gt; 上&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;(2) 导出函数/方法文档&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// ValidateUser checks if the provided user meets all business requirements.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// It validates the user's email format, password strength, and required fields.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// Returns nil if validation passes, or ValidationError if any check fails.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// Example:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//  err := ValidateUser(user)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//  if err != nil {&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//      return err&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//  }&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ValidateUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 实现细节&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;规范要求：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;描述”做什么”，不是”怎么做” - 重点在意图而非实现&lt;/li&gt;
  &lt;li&gt;使用完整句子，以句号结尾&lt;/li&gt;
  &lt;li&gt;提供使用示例（如果复杂）&lt;/li&gt;
  &lt;li&gt;说明参数、返回值、错误情况&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;(3) 导出类型/结构体文档&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Config holds application configuration settings.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// This struct is safe for concurrent use after initialization.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// Host is the server hostname or IP address.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Host&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;host&quot;`&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Port is the server port number (default: 8080).&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Port&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;port&quot;`&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;// Timeout is the request timeout in seconds.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;timeout&quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(4) 导出变量/常量文档&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// DefaultPort is the default HTTP port used when none is specified.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DefaultPort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8080&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// ErrInvalidInput is returned when user input fails validation.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ErrInvalidInput&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;invalid input&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;go-文档的独特优势&quot;&gt;Go 文档的独特优势&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;工具链深度集成&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 查看包文档&lt;/span&gt;
go doc net/http

&lt;span class=&quot;c&quot;&gt;# 查看特定函数&lt;/span&gt;
go doc fmt.Printf

&lt;span class=&quot;c&quot;&gt;# 启动本地文档服务器&lt;/span&gt;
godoc &lt;span class=&quot;nt&quot;&gt;-http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;:6060
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/100_go_mistakes11.png&quot; alt=&quot;100_go_mistakes11&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;文档生成工具链&quot;&gt;文档生成工具链&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;(1) 标准工具&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 格式化文档注释&lt;/span&gt;
go &lt;span class=&quot;nb&quot;&gt;fmt&lt;/span&gt; ./...

&lt;span class=&quot;c&quot;&gt;# 检查文档完整性&lt;/span&gt;
go vet ./...

&lt;span class=&quot;c&quot;&gt;# 专门的文档检查工具&lt;/span&gt;
golang.org/x/tools/go/analysis/passes/doc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;(2) 生成 HTML 文档&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 生成包文档网站&lt;/span&gt;
godoc &lt;span class=&quot;nt&quot;&gt;-url&lt;/span&gt; /pkg/your-package &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; docs.html

&lt;span class=&quot;c&quot;&gt;# 使用pkgsite（Go 1.16+）&lt;/span&gt;
go &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;golang.org/x/pkgsite/cmd/pkgsite@latest
pkgsite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;为什么-go-特别强调文档&quot;&gt;为什么 Go 特别强调文档&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Go 文档是公开 API 契约：&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg.go.dev&lt;/code&gt; 自动为所有公共包生成文档&lt;/li&gt;
  &lt;li&gt;文档驱动开发文化：Go 社区优先考虑清晰、简洁的 API 文档&lt;/li&gt;
  &lt;li&gt;工具链强制执行：&lt;code class=&quot;highlighter-rouge&quot;&gt;go vet&lt;/code&gt; 会检查缺失的文档&lt;/li&gt;
  &lt;li&gt;文档影响包的可发现性：良好的文档提高包的采用率&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在 Go 中，&lt;strong&gt;文档不是可选的附加品，而是代码的核心组成部分&lt;/strong&gt;。良好的文档：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;减少使用成本：用户无需阅读源代码&lt;/li&gt;
  &lt;li&gt;提高维护性：清晰的意图说明&lt;/li&gt;
  &lt;li&gt;增强可靠性：示例即测试&lt;/li&gt;
  &lt;li&gt;促进代码重用：清晰的API契约&lt;/li&gt;
  &lt;li&gt;遵循”文档优先”的原则，把文档作为设计过程的一部分，而不是事后补充。正如 Rob Pike 所说：”&lt;strong&gt;文档是给用户看的，注释是给维护者看的。&lt;/strong&gt;”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;16-not-using-linters-未使用-linters&quot;&gt;16. Not using linters (未使用 linters)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;TL;DR&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;To improve code quality and consistency, use linters and formatters.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A linter is an automatic tool to analyze code and catch errors. The scope of this section isn’t to give an exhaustive list of the existing linters; otherwise, it will become deprecated pretty quickly. But we should understand and remember why linters are essential for most Go projects.&lt;/p&gt;

&lt;p&gt;However, if you’re not a regular user of linters, here is a list that you may want to use daily:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;https://golang.org/cmd/vet—A standard Go analyzer&lt;/li&gt;
  &lt;li&gt;https://github.com/kisielk/errcheck—An error checker&lt;/li&gt;
  &lt;li&gt;https://github.com/fzipp/gocyclo—A cyclomatic complexity analyzer&lt;/li&gt;
  &lt;li&gt;https://github.com/jgautheron/goconst—A repeated string constants analyzer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides linters, we should also use code formatters to fix code style. Here is a list of some code formatters for you to try:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;https://golang.org/cmd/gofmt—A standard Go code formatter&lt;/li&gt;
  &lt;li&gt;https://godoc.org/golang.org/x/tools/cmd/goimports—A standard Go imports formatter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile, we should also look at golangci-lint (https://github.com/golangci/golangci-lint). It’s a linting tool that provides a facade on top of many useful linters and formatters. Also, it allows running the linters in parallel to improve analysis speed, which is quite handy.&lt;/p&gt;

&lt;p&gt;Linters and formatters are a powerful way to improve the quality and consistency of our codebase. Let’s take the time to understand which one we should use and make sure we automate their execution (such as a CI or Git precommit hook).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;核心观点：使用 linter 和格式化工具是提高 Go 代码质量的关键实践。它们能自动发现潜在问题、保持代码一致性，并强制执行最佳实践。&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;data-types&quot;&gt;Data Types&lt;/h1&gt;

&lt;h2 id=&quot;17-creating-confusion-with-octal-literals&quot;&gt;17. Creating confusion with octal literals&lt;/h2&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;https://github.com/teivah/100-go-mistakes&lt;/li&gt;
  &lt;li&gt;https://100go.co/&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="GoLang" /><summary type="html"></summary></entry><entry><title type="html">Pithy Wisdom: Go Proverbs for Philosophy and Pedagogy</title><link href="http://172.19.0.16:8080/golang/2025/12/24/pithy-wisdom-go-proverbs-for-philosophy-and-pedagogy.html" rel="alternate" type="text/html" title="Pithy Wisdom: Go Proverbs for Philosophy and Pedagogy" /><published>2025-12-24T12:30:00+08:00</published><updated>2025-12-24T12:30:00+08:00</updated><id>http://172.19.0.16:8080/golang/2025/12/24/pithy-wisdom-go-proverbs-for-philosophy-and-pedagogy</id><content type="html" xml:base="http://172.19.0.16:8080/golang/2025/12/24/pithy-wisdom-go-proverbs-for-philosophy-and-pedagogy.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#go-箴言的起源与目的&quot; id=&quot;markdown-toc-go-箴言的起源与目的&quot;&gt;Go 箴言的起源与目的&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#关于并发与同步的核心观点&quot; id=&quot;markdown-toc-关于并发与同步的核心观点&quot;&gt;关于并发与同步的核心观点&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#接口与抽象的设计哲学&quot; id=&quot;markdown-toc-接口与抽象的设计哲学&quot;&gt;接口与抽象的设计哲学&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#软件工程与代码质量&quot; id=&quot;markdown-toc-软件工程与代码质量&quot;&gt;软件工程与代码质量&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#错误处理与底层机制&quot; id=&quot;markdown-toc-错误处理与底层机制&quot;&gt;错误处理与底层机制&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#文档与命名&quot; id=&quot;markdown-toc-文档与命名&quot;&gt;文档与命名&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rob Pike 在 2015 年 Gopherfest 上的演讲，探讨了如何通过 &lt;strong&gt;“编程谚语”来传达 Go 语言的核心哲学。他借鉴了围棋中富有诗意且内涵丰富的教导方式，提出了诸如“通过通信共享内存”和“清晰优于聪明”等简洁名言。这些谚语不仅是初学者的教学工具，更封装了关于并发处理、接口设计和依赖管理的深刻工程实践。作者强调，Go 语言的真正力量不仅在于语法，更在于其社区形成的独特编程文化与思维方式&lt;/strong&gt;。通过这些易于记忆的准则，开发者能够更直观地理解如何编写更具可维护性与鲁棒性的代码。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;学习 Go 语言就像学习烹饪。语法是识别食材和刀具，而这些箴言就像是顶级厨师总结出的“火候秘籍”。它们并不规定你必须切多大的块，但会告诉你“过度的调料会掩盖食材的原味”，指引你做出清爽且高质量的佳肴。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=162s&quot;&gt;02:42&lt;/a&gt; Don’t communicate by sharing memory, share memory by communicating.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=222s&quot;&gt;03:42&lt;/a&gt; Concurrency is not parallelism.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=260s&quot;&gt;04:20&lt;/a&gt; Channels orchestrate; mutexes serialize.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=318s&quot;&gt;05:18&lt;/a&gt; The bigger the interface, the weaker the abstraction.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=385s&quot;&gt;06:25&lt;/a&gt; Make the zero value useful.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=456s&quot;&gt;07:36&lt;/a&gt; interface{} says nothing.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=523s&quot;&gt;08:43&lt;/a&gt; Gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=568s&quot;&gt;09:28&lt;/a&gt; A little copying is better than a little dependency.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=670s&quot;&gt;11:10&lt;/a&gt; Syscall must always be guarded with build tags.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=712s&quot;&gt;11:52&lt;/a&gt; Cgo must always be guarded with build tags.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=757s&quot;&gt;12:37&lt;/a&gt; Cgo is not Go.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=830s&quot;&gt;13:50&lt;/a&gt; With the unsafe package there are no guarantees.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=874s&quot;&gt;14:34&lt;/a&gt; Clear is better than clever.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=923s&quot;&gt;15:23&lt;/a&gt; Reflection is never clear.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=973s&quot;&gt;16:13&lt;/a&gt; Errors are values.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=1047s&quot;&gt;17:27&lt;/a&gt; Don’t just check errors, handle them gracefully.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=1090s&quot;&gt;18:10&lt;/a&gt; Design the architecture, name the components, document the details.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=1148s&quot;&gt;19:08&lt;/a&gt; Documentation is for users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm19.png&quot; alt=&quot;notebooklm19&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;go-箴言的起源与目的&quot;&gt;Go 箴言的起源与目的&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;灵感来源&lt;/strong&gt;：概念源自围棋（&lt;a href=&quot;https://en.wikipedia.org/wiki/Go_(game)&quot;&gt;Go game&lt;/a&gt;）中的“围棋谚语”，用于向学习者传授复杂的模式和策略。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;教学价值&lt;/strong&gt;：它们被用作一种&lt;strong&gt;教学工具（Pedagogy）&lt;/strong&gt;，帮助开发者超越简单的语法学习，理解 Go 语言背后的深层哲学和架构决策。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;核心特性&lt;/strong&gt;：有效的箴言应当是&lt;strong&gt;简短、通用且具有启发性的&lt;/strong&gt;，即使它们在某些工程场景下可能互相对立。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;关于并发与同步的核心观点&quot;&gt;关于并发与同步的核心观点&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;不要通过共享内存来通信，而要通过通信来共享内存&lt;/strong&gt;：这是最著名的 Go 箴言，强调通过通道（Channel）传递指针或对象所有权，以实现安全的并发。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;并发（Concurrency）不等于并行（Parallelism）&lt;/strong&gt;：并发是关于&lt;strong&gt;程序结构的组织&lt;/strong&gt;（使其可扩展、易理解），而并行是关于多任务的&lt;strong&gt;同时执行&lt;/strong&gt;。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;通道负责编排，互斥锁负责序列化&lt;/strong&gt;：互斥锁（Mutexes）用于细粒度的内存保护，而通道（Channels）用于协调程序的大规模结构。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;接口与抽象的设计哲学&quot;&gt;接口与抽象的设计哲学&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;接口越大，抽象越弱&lt;/strong&gt;：强大的抽象（如 &lt;code class=&quot;highlighter-rouge&quot;&gt;io.Reader&lt;/code&gt;）通常只有极少的方法。接口越小，复用性和组合性就越强。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;空接口（&lt;code class=&quot;highlighter-rouge&quot;&gt;interface{}&lt;/code&gt;）不传达任何信息&lt;/strong&gt;：过度使用空接口会丧失静态检查的优势。开发者应尽量定义具体的接口方法来明确意图。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;软件工程与代码质量&quot;&gt;软件工程与代码质量&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;让零值（&lt;code class=&quot;highlighter-rouge&quot;&gt;Zero Value&lt;/code&gt;）变得有用&lt;/strong&gt;：优秀的 API 设计应确保类型的零值无需显式初始化即可直接使用（如 &lt;code class=&quot;highlighter-rouge&quot;&gt;sync.Mutex&lt;/code&gt; 或 &lt;code class=&quot;highlighter-rouge&quot;&gt;bytes.Buffer&lt;/code&gt;）&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;宁可少量的拷贝，也不要增加依赖&lt;/strong&gt;：为了保持依赖树的精简和编译速度，有时拷贝几行代码比引入一个庞大的库更明智。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;清晰胜过聪明&lt;/strong&gt;：Go 追求代码的可维护性和稳定性，不鼓励追求极度紧凑或深奥的“聪明”写法。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;gofmt&lt;/code&gt; 的风格没人喜欢，但它是每个人的最爱&lt;/strong&gt;：标准化的格式化工具虽然不能满足所有人的审美，但消除了关于代码样式的无谓争论。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;错误处理与底层机制&quot;&gt;错误处理与底层机制&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;错误是值（&lt;code class=&quot;highlighter-rouge&quot;&gt;Errors are values&lt;/code&gt;）&lt;/strong&gt;：不要仅仅把错误当成异常处理，它们是可以被编程、存储和传递的对象。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;不要只检查错误，要优雅地处理它们&lt;/strong&gt;：开发者应考虑如何对错误进行包装或根据错误采取具体行动，而不仅仅是向上层返回。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;警惕 Cgo、Unsafe 和反射&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;CGO 不是 Go&lt;/strong&gt;：使用 CGO 会破坏内存安全、垃圾回收和跨平台稳定性。&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;反射永不清晰&lt;/strong&gt;：反射非常强大但难以使用且缺乏编译时检查，建议初学者远离。&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;unsafe 包没有任何保证&lt;/strong&gt;：使用它意味着代码可能在未来的版本中失效。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;文档与命名&quot;&gt;文档与命名&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;设计架构，命名组件，记录细节&lt;/strong&gt;：良好的命名应承担表达设计意图的主要责任。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;文档是给用户看的&lt;/strong&gt;：编写文档（GoDoc）时应站在使用者的角度，而非实现者的角度。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PAAkCSZUG1c&quot;&gt;Gopherfest 2015 - Go Proverbs with Rob Pike&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;https://www.youtube.com/@golang&lt;/li&gt;
  &lt;li&gt;https://notebooklm.google.com/notebook/fe1d8b50-fdaa-4be5-aa92-524039b32f81 (NotebookLM 解读)&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="GoLang" /><summary type="html"></summary></entry><entry><title type="html">NotebookLM in Action</title><link href="http://172.19.0.16:8080/ml/2025/12/24/notebooklm-in-action.html" rel="alternate" type="text/html" title="NotebookLM in Action" /><published>2025-12-24T08:30:00+08:00</published><updated>2025-12-24T08:30:00+08:00</updated><id>http://172.19.0.16:8080/ml/2025/12/24/notebooklm-in-action</id><content type="html" xml:base="http://172.19.0.16:8080/ml/2025/12/24/notebooklm-in-action.html">&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#核心功能&quot; id=&quot;markdown-toc-核心功能&quot;&gt;核心功能&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#使用场景&quot; id=&quot;markdown-toc-使用场景&quot;&gt;使用场景&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#使用方法&quot; id=&quot;markdown-toc-使用方法&quot;&gt;使用方法&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#实用技巧与注意事项&quot; id=&quot;markdown-toc-实用技巧与注意事项&quot;&gt;实用技巧与注意事项&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#使用示例&quot; id=&quot;markdown-toc-使用示例&quot;&gt;使用示例&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#生成中文的音频&quot; id=&quot;markdown-toc-生成中文的音频&quot;&gt;生成中文的音频&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#生成思维导图&quot; id=&quot;markdown-toc-生成思维导图&quot;&gt;生成思维导图&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#输出报告&quot; id=&quot;markdown-toc-输出报告&quot;&gt;输出报告&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#生成闪卡&quot; id=&quot;markdown-toc-生成闪卡&quot;&gt;生成闪卡&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#测验&quot; id=&quot;markdown-toc-测验&quot;&gt;测验&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#信息图&quot; id=&quot;markdown-toc-信息图&quot;&gt;信息图&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#演示文稿&quot; id=&quot;markdown-toc-演示文稿&quot;&gt;演示文稿&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#限额问题&quot; id=&quot;markdown-toc-限额问题&quot;&gt;限额问题&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#refer&quot; id=&quot;markdown-toc-refer&quot;&gt;Refer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;参考 &lt;a href=&quot;https://zh.wikipedia.org/zh-cn/NotebookLM&quot;&gt;NotebookLM 的维基百科&lt;/a&gt;，NotebookLM 是 Google 实验室推出的一款在线笔记本，NotebookLM 内置 Gemini，它可以根据用户上传的内容生成摘要、注解和用户想要的答案。除了文本文件，用户还可以上传 PDF 文档格式、Google 文档、网站和 Google 演示稿。此外用户上传文件后，NotebookLM 可以根据文件内容生成 Podcast 以及音频文件，并在 Podcast 中概述文件内容。NotebookLM 于 &lt;strong&gt;2023&lt;/strong&gt; 年推出，当时名为 &lt;strong&gt;Project Tailwind&lt;/strong&gt;。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Notebook + Language Model = NotebookLM&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;其核心理念是 “先给你的 AI 提供资料，再让它基于资料帮你工作” 。它不像 ChatGPT 那样拥有通用知识库，而是专注于分析和理解你上传的文档，并在此基础上与你深度互动。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NotebookLM&lt;/strong&gt; 是一个强大的“第二大脑”或“研究副驾驶”。它最适合那些需要深度处理、消化和转化现有文档信息的任务，将静态资料转化为动态的、可交互的知识库，显著提升研究和内容创作的效率。&lt;/p&gt;

&lt;h1 id=&quot;核心功能&quot;&gt;核心功能&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;资料源驱动&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;可以上传多种格式的文档（PDF、TXT、Word、Google Docs、甚至复制粘贴的文本）。&lt;/li&gt;
  &lt;li&gt;AI 的知识范围将严格限定在你提供的资料内，回答会带有引用来源（指向原文的特定段落），大大提高了可信度和可追溯性。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;三大核心功能&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;总结与问答&lt;/strong&gt;：快速生成文档摘要、提取关键要点，并可以针对文档内容进行深度提问。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;创意生成&lt;/strong&gt;：基于你提供的资料，生成新的内容，如博客文章大纲、营销邮件、剧本创意、学习计划等。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;思维拓展&lt;/strong&gt;：帮你连接不同文档中的观点，或基于资料进行批判性思考和分析。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;“笔记本”工作区：&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;每个项目都是一个“笔记本”，你可以持续向其中添加多个相关文档（目前最多 50 个），构建一个专属的知识库。&lt;/p&gt;

&lt;h1 id=&quot;使用场景&quot;&gt;使用场景&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;学术研究&lt;/strong&gt;：学生可以上传论文、教科书章节，让 NotebookLM 总结要点、解释复杂概念、准备考试问答。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;内容创作&lt;/strong&gt;：创作者上传采访记录、背景资料，让 AI 帮忙起草文章、生成创意角度或社交媒体帖子。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;商业分析&lt;/strong&gt;：上传市场报告、会议纪要、竞争对手信息，快速生成综合分析、SWOT 分析或执行摘要。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;个人知识管理&lt;/strong&gt;：阅读大量资料时，上传所有内容，让AI帮你梳理脉络、提炼核心思想，形成个人知识库。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;高效阅读&lt;/strong&gt;：快速消化长文档、法律合同或技术手册，通过问答快速定位关键信息。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;使用方法&quot;&gt;使用方法&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;访问与创建&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;访问 &lt;a href=&quot;https://notebooklm.google.com/&quot;&gt;NotebookLM 官网&lt;/a&gt;，使用谷歌账号登录。&lt;/li&gt;
      &lt;li&gt;点击 “New Notebook” 创建一个新笔记本，并为其命名。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;上传资料&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;在笔记本中，点击 “Add source”（添加来源）。&lt;/li&gt;
      &lt;li&gt;选择上传文件（支持 PDF、DOCX、TXT 等）、粘贴文本，或直接导入 Google Docs。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;与AI互动&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;资料上传后，右侧的 AI 聊天界面会自动激活。&lt;/li&gt;
      &lt;li&gt;自动生成建议问题：NotebookLM 会基于文档内容，自动在界面左侧生成几个推荐问题，点击即可快速提问。&lt;/li&gt;
      &lt;li&gt;自由提问：你也可以在底部的输入框中提出任何关于文档内容的问题。&lt;/li&gt;
      &lt;li&gt;使用功能按钮：界面提供了一些快捷功能按钮，如“Summarize this”（总结）、“Create study guide”（创建学习指南）等，一键生成所需内容。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;进行创意写作&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;告诉 AI 你的写作目标（例如：“基于这三份资料，写一封向客户介绍新功能的邮件”）。&lt;/li&gt;
      &lt;li&gt;AI 会生成草稿，你可以要求它调整语气、长度或重点。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;管理多个资料源&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;在一个笔记本中添加所有相关文档，AI 会交叉引用所有内容来回答问题，实现知识的融合。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;实用技巧与注意事项&quot;&gt;实用技巧与注意事项&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;从具体问题开始&lt;/strong&gt;：问题越具体，得到的答案越精确。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;要求引用来源&lt;/strong&gt;：对于关键信息，可以追问“这个观点在原文的哪一部分？”，AI 会高亮显示原文出处。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;多轮对话&lt;/strong&gt;：像与专家对话一样，可以基于上一个回答深入追问，进行层层剖析。&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;目前限制&lt;/strong&gt;：处于实验阶段，免费使用，但可能有时长或功能限制；处理非英语资料的能力可能较弱；对上传的文档数量有上限。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;使用示例&quot;&gt;使用示例&lt;/h1&gt;

&lt;p&gt;以 YouTube 上的 &lt;a href=&quot;https://www.youtube.com/watch?v=PfbFtY0aHbI&quot;&gt;How to achieve concurrency&lt;/a&gt; 的视频为例：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm.png&quot; alt=&quot;notebooklm&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm2.png&quot; alt=&quot;notebooklm2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm3.png&quot; alt=&quot;notebooklm3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;导入后会生成如下信息：https://notebooklm.google.com/notebook/db903978-6d35-4aac-a877-ce974b9820b4&lt;/p&gt;

&lt;p&gt;这段视频教程介绍了如何利用 Go 语言 的原生特性来优化程序执行效率。作者指出，传统的同步处理方式在面对文件读写等耗时操作时速度较慢，而通过 Goroutines（协程） 可以同时独立运行多个任务。为了管理这些并发任务，开发者可以使用 Channels（通道） 像管道一样在不同进程间传递数据。这种机制不仅能实现异步编程，还能确保主程序在获取到必要结果前处于自动阻塞等待状态。通过结合这两大核心功能，程序员能够以更简洁的代码处理复杂的并发任务。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm4.png&quot; alt=&quot;notebooklm4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;主要有以下几个功能：&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;生成中文的音频&quot;&gt;生成中文的音频&lt;/h2&gt;

&lt;p&gt;可以对此内容生成&lt;strong&gt;中文的音频概览&lt;/strong&gt;，对于英文不好的用户比较友好，但是免费场景，&lt;strong&gt;每日有使用次数限制&lt;/strong&gt;。&lt;/p&gt;

&lt;h2 id=&quot;生成思维导图&quot;&gt;生成思维导图&lt;/h2&gt;

&lt;p&gt;支持&lt;strong&gt;生成思维导图&lt;/strong&gt;，并可以根据思维导图选择的关键信息进行 &lt;strong&gt;Deep Research 深度解释&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm9.png&quot; alt=&quot;notebooklm9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm10.png&quot; alt=&quot;notebooklm10&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;输出报告&quot;&gt;输出报告&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm11.png&quot; alt=&quot;notebooklm11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;输出一份最佳实践报告：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm12.png&quot; alt=&quot;notebooklm12&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;生成闪卡&quot;&gt;生成闪卡&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm13.gif&quot; alt=&quot;notebooklm13&quot; /&gt;&lt;/p&gt;

&lt;p&gt;同时支持导出：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm14.png&quot; alt=&quot;notebooklm14&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;测验&quot;&gt;测验&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm15.gif&quot; alt=&quot;notebooklm15&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;信息图&quot;&gt;信息图&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm16.png&quot; alt=&quot;notebooklm16&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;演示文稿&quot;&gt;演示文稿&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm17.gif&quot; alt=&quot;notebooklm17&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;限额问题&quot;&gt;限额问题&lt;/h1&gt;

&lt;p&gt;升级到 Google AI Pro，获享更高的 NotebookLM 限额及更多福利。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;精选方案：https://one.google.com/u/0/explore-plan/notebooklm?utm_source=notebooklm&amp;amp;utm_medium=web&amp;amp;utm_campaign=audio_overview_limit&amp;amp;ms=pt:1285;s:532;vp:9&lt;/li&gt;
  &lt;li&gt;更多方案：https://one.google.com/ai?g1_last_touchpoint=62&amp;amp;g1_landing_page=75&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm7.png&quot; alt=&quot;notebooklm7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm5.png&quot; alt=&quot;notebooklm5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm6.png&quot; alt=&quot;notebooklm6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/202512/notebooklm8.png&quot; alt=&quot;notebooklm8&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;refer&quot;&gt;Refer&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;https://notebooklm.google.com/&lt;/li&gt;
  &lt;li&gt;https://zh.wikipedia.org/zh-cn/NotebookLM&lt;/li&gt;
&lt;/ul&gt;</content><author><name>gerryyang</name></author><category term="ML" /><summary type="html"></summary></entry></feed>