<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>代码记录 on Jarao&#39;s Blog</title>
        <link>https://blog.jarao.work/categories/code/</link>
        <description>Recent content in 代码记录 on Jarao&#39;s Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Thu, 27 Jul 2023 11:12:44 +0800</lastBuildDate><atom:link href="https://blog.jarao.work/categories/code/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>约定式提交 Conventional Commits</title>
        <link>https://blog.jarao.work/articles/2023/07/conventional-commits/</link>
        <pubDate>Thu, 27 Jul 2023 11:12:44 +0800</pubDate>
        
        <guid>https://blog.jarao.work/articles/2023/07/conventional-commits/</guid>
        <description>&lt;img src="https://blog.jarao.work/articles/2023/07/conventional-commits/cover.png" alt="Featured image of post 约定式提交 Conventional Commits" /&gt;&lt;p&gt;前段时间在公司提交代码的时候，看到仓库密密麻麻格式不一的commit记录有点头疼🤣，去问了下同事发现这块好像大家普遍都不注重，因此专门做了下关于约定式提交的调查。&lt;/p&gt;
&lt;h2 id=&#34;为什么要规范commit&#34;&gt;为什么要规范commit
&lt;/h2&gt;&lt;p&gt;代码的Git提交是每个项目必经且十分频繁的操作，一个大型的、长期的项目如果在没有commit规范的情况下进行迭代，在经由不同的时期、不同的团队迭代后，commit记录会出现五花八门的格式，一是每个人的信息格式不一致会导致查阅者获取关键信息的效率低，二是时间久了就会出现因commit消息不清晰导致无法有效追溯变更记录。&lt;/p&gt;
&lt;p&gt;这种情况在开源社区更是常见，因此基本上所有大型的开源项目为了保证信息规整有效，都会设立对应项目的commit规范。这不仅对于获取commit有效信息有很大的帮助，同时会让一个开发者去注意思考每次commit的功能、特性划分的合理性，如果配合一定的工具，还能够简便的生成规范的release日志。&lt;/p&gt;
&lt;p&gt;其实说白了主要目的就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;规范代码commit的信息，提高获取关键信息的效率，减少因团队更迭后造成的信息出入&lt;/li&gt;
&lt;li&gt;通过git工具，快速生成标准release日志&lt;/li&gt;
&lt;li&gt;获得共识，对齐业界（好歹别太low对吧🤪）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;业界调研&#34;&gt;业界调研
&lt;/h2&gt;&lt;p&gt;当前我所在的公司没有commit的明确规范标准，而业界当前大部分的commit规范是基于「&lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Angular Commit Guidelines&lt;/a&gt;&lt;/strong&gt;」，这是一个js的commit规范，但是由于其定义的严谨性和通用性而被大部分项目采纳。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;实际上这块还涉及一个版本号管理规范「&lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://semver.org/lang/zh-CN/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;语义化版本 2.0.0 | Semantic Versioning&lt;/a&gt;&lt;/strong&gt;」，起初也是前端为了管理包版本设计的）&lt;/em&gt;&lt;/p&gt;


&lt;div style=&#34;overflow-x: auto;&#34;&gt;
&lt;table style=&#34;width: 1200px;margin: 0;&#34;&gt;
    &lt;tr&gt;
        &lt;th&gt;项目&lt;/th&gt;
        &lt;td&gt;Blocky&lt;/td&gt;
        &lt;td&gt;React&lt;/td&gt;
        &lt;td&gt;高德地图&lt;/td&gt;
        &lt;td&gt;Bootstrap&lt;/td&gt;
        &lt;td&gt;nginx&lt;/td&gt;
        &lt;td&gt;electron&lt;/td&gt;
        &lt;td&gt;openwrt&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;th&gt;公司（社区）&lt;/th&gt;
        &lt;td&gt;Google&lt;/td&gt;
        &lt;td&gt;Meta&lt;/td&gt;
        &lt;td&gt;阿里&lt;/td&gt;
        &lt;td&gt;Twitter&lt;/td&gt;
        &lt;td&gt;nginx&lt;/td&gt;
        &lt;td&gt;electron&lt;/td&gt;
        &lt;td&gt;openwrt/lede&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;th&gt;commit规范&lt;/th&gt;
        &lt;td&gt;&lt;a href=&#34;https://www.conventionalcommits.org/zh-hans/v1.0.0/&#34;&gt;约定式提交（基于 Angular Commit Guidelines）&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit&#34;&gt;Angular Commit Guidelines&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/182553920&#34;&gt;如何规范你的Git commit？（基于Angular Commit Guidelines）&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&#34;&gt;tbaggery - A Note About Git Commit Messages&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;http://nginx.org/en/docs/contributing_changes.html&#34;&gt;Contributing Changes (nginx.org)&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;https://www.conventionalcommits.org/zh-hans/v1.0.0/&#34;&gt;约定式提交（基于 Angular Commit Guidelines）&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;a href=&#34;https://openwrt.org/submitting-patches&#34;&gt;[OpenWrt Wiki] Submitting patches&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;th&gt;共性&lt;/th&gt;
        &lt;td colspan=&#34;7&#34;&gt;
            1. 以commit类型为开头，例如feat，fix，build&lt;br&gt;
            2. 类型后紧跟描述信息&lt;br&gt;
            3. subject或description长度不是都限制，但一般不宜超过50~100，力求言简意赅&lt;br&gt;
            4. body、footer可选，可以没有&lt;br&gt;
            5. 不在末尾增加句号&lt;br&gt;
            6. 会根据项目特性进行适当调整
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Angular Commit Guidelines&lt;/strong&gt;文档介绍中提及了「&lt;strong&gt;&lt;a class=&#34;link&#34; href=&#34;https://google.github.io/styleguide/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Google Style Guides | styleguide&lt;/a&gt;&lt;/strong&gt;」，其部分设计思路是遵循该文档。&lt;/p&gt;
&lt;h2 id=&#34;约定式提交使用介绍&#34;&gt;约定式提交使用介绍
&lt;/h2&gt;&lt;h3 id=&#34;特点&#34;&gt;特点
&lt;/h3&gt;&lt;p&gt;约定式提交则在保留了Angular规范的基础上，进行了部分调整和优化，例如明确允许scope的内容可选填（实际上阿里的规范也有这个优化，业内社区也普遍没有要求scope内容）；在具有破坏性的commit上使用「!」标记（对标SemVer强调破坏性提交的特点）等，并且谷歌、electorn等公司、项目也有使用，也算是受到业界认可的规范标准。&lt;/p&gt;
&lt;p&gt;当然还有最重要的一点是，&lt;strong&gt;他有专门的社区维护，文档十分的完善&lt;/strong&gt;，基本我们可以做到开箱即用，并且社区也提供了一些自动化工具。&lt;/p&gt;
&lt;p&gt;具体规范我就不过多介绍（因为官方文档真的很详细了），以下摘抄一部分官方文档，可以感受下。&lt;/p&gt;
&lt;h3 id=&#34;官方文档&#34;&gt;官方文档
&lt;/h3&gt;&lt;h4 id=&#34;概述&#34;&gt;概述
&lt;/h4&gt;&lt;p&gt;约定式提交规范是一种基于提交信息的轻量级约定。
它提供了一组简单规则来创建清晰的提交历史；
这更有利于编写自动化工具。
通过在提交信息中描述功能、修复和破坏性变更，
使这种惯例与 &lt;a class=&#34;link&#34; href=&#34;http://semver.org/lang/zh-CN&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;SemVer&lt;/a&gt; 相互对应。&lt;/p&gt;
&lt;p&gt;提交说明的结构如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;类型&amp;gt;[可选 范围]: &amp;lt;描述&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[可选 正文]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[可选 脚注]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;提交说明包含了下面的结构化元素，以向类库使用者表明其意图：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fix: 类型 为 fix 的提交表示在代码库中修复了一个 bug（这和语义化版本中的 PATCH 相对应）。&lt;/li&gt;
&lt;li&gt;feat: 类型 为 feat 的提交表示在代码库中新增了一个功能（这和语义化版本中的 MINOR 相对应）。&lt;/li&gt;
&lt;li&gt;BREAKING CHANGE: 在脚注中包含 BREAKING CHANGE: 或 &amp;lt;类型&amp;gt;(范围) 后面有一个 ! 的提交，表示引入了破坏性 API 变更（这和语义化版本中的 MAJOR 相对应）。 破坏性变更可以是任意 类型 提交的一部分。&lt;/li&gt;
&lt;li&gt;除 fix: 和 feat: 之外，也可以使用其它提交 类型 ，例如 @commitlint/config-conventional（基于 Angular 约定）中推荐的 build:、chore:、 ci:、docs:、style:、refactor:、perf:、test:，等等。&lt;/li&gt;
&lt;li&gt;脚注中除了 BREAKING CHANGE: &lt;description&gt; ，其它条目应该采用类似 git trailer format 这样的惯例。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其它提交类型在约定式提交规范中并没有强制限制，并且在语义化版本中没有隐式影响（除非它们包含 BREAKING CHANGE）。 可以为提交类型添加一个围在圆括号内的范围，以为其提供额外的上下文信息。例如 &lt;code&gt;feat(parser): adds ability to parse arrays.&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;示例&#34;&gt;示例
&lt;/h4&gt;&lt;p&gt;包含了描述并且脚注中有破坏性变更的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;feat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;allow&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;provided&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extend&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configs&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BREAKING&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CHANGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extends&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;is&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;used&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extending&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;包含了 ! 字符以提醒注意破坏性变更的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;feat!: send an email to the customer when a product is shipped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;包含了范围和破坏性变更 ! 的提交說明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;feat(api)!: send an email to the customer when a product is shipped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;包含了 ! 和 BREAKING CHANGE 脚注的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chore!: drop support for Node 6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BREAKING CHANGE: use JavaScript features not available in Node 6.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;不包含正文的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docs: correct spelling of CHANGELOG
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;包含范围的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;feat(lang): add polish language
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;包含多行正文和多行脚注的提交说明&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fix: prevent racing of requests
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Introduce a request id and a reference to latest request. Dismiss
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;incoming responses other than from latest request.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Remove timeouts which were used to mitigate the racing issue but are
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;obsolete now.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reviewed-by: Z
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Refs: #123
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id=&#34;为什么使用约定式提交&#34;&gt;为什么使用约定式提交
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;自动化生成 CHANGELOG。&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;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;根据commit生成release日志&#34;&gt;根据commit生成release日志
&lt;/h2&gt;&lt;p&gt;既然commit有了固定的格式，那我们自然可以根据这个格式来生成标准的日志啦&lt;br&gt;
由于公司项目不是前端项目，也不是新项目，实在没法使用社区里自带的日志生成工具，于是就自己写了段shell支持🫠&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git log --pretty&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;format:&lt;span class=&#34;s2&#34;&gt;&amp;#34;%s https://url/commit/%H&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;git show-ref --tags &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;project/v&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;END{print}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;/,$d&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;grep -E &lt;span class=&#34;s2&#34;&gt;&amp;#34;^(feat|fix|refactor|chore): &amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;grep -v Merge &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk -F&lt;span class=&#34;s1&#34;&gt;&amp;#39;: &amp;#39;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;{print &amp;#34;[&amp;#34;$1&amp;#34;]&amp;#34;,$2}&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s:\[feat\]:\[feature\]:g&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s:\[fix\]:\[bugfix\]:g&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://blog.jarao.work/articles/2023/07/conventional-commits/img.png&#34;
	width=&#34;1608&#34;
	height=&#34;224&#34;
	srcset=&#34;https://blog.jarao.work/articles/2023/07/conventional-commits/img_hu_ace650a889cef74.png 480w, https://blog.jarao.work/articles/2023/07/conventional-commits/img_hu_6aa19192f5677c71.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;效果图&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;717&#34;
		data-flex-basis=&#34;1722px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;已经分享给公司的同事，希望今后团队commit能有改善吧🤣&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;相关文档：&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.conventionalcommits.org/zh-hans/v1.0.0/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;约定式提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Angular Commit Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://google.github.io/styleguide/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Google Style Guides | styleguide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://semver.org/lang/zh-CN/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;语义化版本 2.0.0 | Semantic Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://zhuanlan.zhihu.com/p/182553920&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;如何规范你的Git commit？（基于Angular Commit Guidelines）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://openwrt.org/submitting-patches&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;[OpenWrt Wiki] Submitting patches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;tbaggery - A Note About Git Commit Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;http://nginx.org/en/docs/contributing_changes.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Contributing Changes (nginx.org)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Go泛型学习笔记</title>
        <link>https://blog.jarao.work/articles/2022/03/learn-go-generic/</link>
        <pubDate>Thu, 24 Mar 2022 21:04:21 +0800</pubDate>
        
        <guid>https://blog.jarao.work/articles/2022/03/learn-go-generic/</guid>
        <description>&lt;img src="https://blog.jarao.work/articles/2022/03/learn-go-generic/cover.png" alt="Featured image of post Go泛型学习笔记" /&gt;&lt;p&gt;&lt;em&gt;封面PID=98135423&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Go自从1.18开始正式支持了泛型，官方称其为Go开源发布之后最大的一次变更。&lt;br&gt;
在出现泛型之前，Go传递不定参数的通用方法是传递接口，这次支持泛型无疑是对Go编码影响巨大的升级。&lt;/p&gt;
&lt;p&gt;本文针对学习过程中的一些要点做初步记录。&lt;/p&gt;
&lt;h2 id=&#34;泛型&#34;&gt;泛型
&lt;/h2&gt;&lt;p&gt;Go支持了泛型，为其带来了三个新的特性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Type parameters for function and types.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Defining interface types as sets of types, including types that don’t have methods.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Type inference, which permits omitting type arguments in many cases when calling a function.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;简单来说，就是支持了函数、type关键字的类型参数，使用无方法接口实现类型集，函数调用泛型推理省略类型参数。&lt;/p&gt;
&lt;p&gt;以下是参照Go的官方例子做的示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 无方法接口实现类型集&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Number&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 函数类型参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GMin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;](&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;em&gt;Hit:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类型参数用&lt;code&gt;[]&lt;/code&gt;来进行定义，泛型标识符&lt;code&gt;T&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Go的编译器会在替换泛型标识符后检查实际类型是否满足函数的类型约束条件。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 这一步编译器会进行函数实例化，如果类型不满足函数内部约束条件（本例里是运算符 &amp;#39;&amp;lt;&amp;#39; ），则会报错&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmin&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;GMin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// float64在这就是实际指定的类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fmin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.71&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// 实例化成功后可正常调用 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;// 2.71&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中Go在进行编译时会进行类型推算（&lt;em&gt;type inference&lt;/em&gt;），因此你也可以将你的函数写成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GMin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;2.71&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// 不需要手动指定T的真实类型，Go自己推算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Println&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;// 2.71&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;以上是一个简单的Go泛型函数调用，其中我们可以看到Go使用了接口关键字&lt;code&gt;interface&lt;/code&gt;关键字来定义泛型的约束类型。
接下来我们就说说为啥Go是用&lt;code&gt;interface&lt;/code&gt;来定义泛型的约束类型集。&lt;/p&gt;
&lt;h2 id=&#34;泛型约束集&#34;&gt;泛型约束集
&lt;/h2&gt;&lt;p&gt;接口定义了一系列方法，实现了这些方法的type可以表现成&lt;code&gt;type-&amp;gt;接口&lt;/code&gt;的一种映射关系；从另一个角度上来说，接口同样定义了一个实现了这些方法的type的集合，这个集合中的type都实现了接口的方法。因此我们反过来可以获得&lt;code&gt;接口-&amp;gt;type&lt;/code&gt;的映射关系&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.jarao.work/articles/2022/03/learn-go-generic/method-sets.png&#34;
	width=&#34;2150&#34;
	height=&#34;1038&#34;
	srcset=&#34;https://blog.jarao.work/articles/2022/03/learn-go-generic/method-sets_hu_8b8fa129f571a27.png 480w, https://blog.jarao.work/articles/2022/03/learn-go-generic/method-sets_hu_3c41578375681e88.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;207&#34;
		data-flex-basis=&#34;497px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;官方博客里的这张图片里展示了一个接口在被多个type实现时所具有的集合关系，其中每一个圈都是一个接口的方法集。可以看到，type&lt;code&gt;P、Q、R&lt;/code&gt;在实现了&lt;code&gt;interface&lt;/code&gt;后，会在中心区域有一个“方法交集”。这个交集反过来定义了下图的类型集。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.jarao.work/articles/2022/03/learn-go-generic/type-sets.png&#34;
	width=&#34;2220&#34;
	height=&#34;1024&#34;
	srcset=&#34;https://blog.jarao.work/articles/2022/03/learn-go-generic/type-sets_hu_7f5fa74861d75969.png 480w, https://blog.jarao.work/articles/2022/03/learn-go-generic/type-sets_hu_93542f3bacb345cf.png 1024w&#34;
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;216&#34;
		data-flex-basis=&#34;520px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;一般的接口是方法的接口，这里泛型的接口可以理解为类型的接口。&lt;/p&gt;
&lt;p&gt;Go的泛型还支持指定某个&lt;em&gt;Underlying Type&lt;/em&gt;，例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Number&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上述代码中，&lt;code&gt;~int&lt;/code&gt;表示所有以int为&lt;em&gt;Underlying Type&lt;/em&gt;的类型。&lt;/p&gt;
&lt;h2 id=&#34;泛型的core-type&#34;&gt;泛型的Core Type
&lt;/h2&gt;&lt;p&gt;需要注意的是Go的在使用内置函数的时候需要确定类型的&lt;em&gt;Core Type&lt;/em&gt;，比如使用&lt;code&gt;make&lt;/code&gt;、&lt;code&gt;range&lt;/code&gt;等操作。如果你的泛型interface没有&lt;em&gt;Core Type&lt;/em&gt;，你会看到类似如下报错&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;NumberSlice&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;float64&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;NumberSlice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;](&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// cannot range over num (variable of type T constrained by NumberSlice) (T has no core type)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;v&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// do something&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这是因为Go定义类型接口的&lt;em&gt;Core Type&lt;/em&gt;只在两种情况存在：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;接口类型集存在统一的&lt;em&gt;Underlying Type&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;接口类型集存在统一的管道，管道的类型、方向需一致&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;像上面的代码，&lt;code&gt;NumberSlice&lt;/code&gt;由于不存在相同的&lt;em&gt;Underlying Type&lt;/em&gt;，因此不具有&lt;em&gt;Core Type&lt;/em&gt;，不能使用&lt;code&gt;range&lt;/code&gt;关键字进行操作。不过我们可以通过调整泛型来实现相同的功能：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Number&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;float64&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;](&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;v&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		 &lt;span class=&#34;c1&#34;&gt;// do something&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样就可以正常的实现遍历泛型slice了。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;相关文档&lt;/em&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://go.dev/ref/spec#Core_types&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The Go Programming Language Specification: Core Type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://go.dev/blog/intro-generics&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;An Introduction To Generics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
