<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>第 4 章 类型系统 on Go 语言原本</title><link>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/</link><description>Recent content in 第 4 章 类型系统 on Go 语言原本</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/index.xml" rel="self" type="application/rss+xml"/><item><title>4.1 运行时类型系统</title><link>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/type/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/type/</guid><description>&lt;h1 id="41-运行时类型系统"&gt;4.1 运行时类型系统&lt;/h1&gt;
&lt;p&gt;Go 是静态类型语言，类型检查发生在编译期。但 Go 又保留了相当一部分&lt;strong&gt;运行时类型信息&lt;/strong&gt;（runtime
type information, RTTI），正是它支撑起了接口（&lt;a href=".././interface"&gt;4.2&lt;/a&gt;）、类型断言、类型 switch、
反射，以及垃圾回收对指针的精确识别。这一节回答一个看似简单的问题：编译期那套类型，到了运行时
还剩下什么、以什么形式留存、又撑起了哪些能力。读懂这一节里那个叫&lt;strong&gt;类型描述符&lt;/strong&gt;的小结构，
后面的接口（&lt;a href=".././interface"&gt;4.2&lt;/a&gt;）、反射与精确 GC（&lt;a href="../../part4memory/ch13gc"&gt;13&lt;/a&gt;）就都有了共同的
落脚点。&lt;/p&gt;
&lt;p&gt;下文给出的结构体都是&lt;strong&gt;裁剪后的速写&lt;/strong&gt;：只保留与设计相关的字段，并在注释里说明它为何存在。
完整定义可对照 go1.26 的 &lt;code&gt;internal/abi/type.go&lt;/code&gt; 与 &lt;code&gt;reflect&lt;/code&gt; 包。&lt;/p&gt;
&lt;h2 id="411-每个类型都有一个描述符"&gt;4.1.1 每个类型都有一个描述符&lt;/h2&gt;
&lt;p&gt;编译器为程序里用到的&lt;strong&gt;每一个类型&lt;/strong&gt;生成一份&lt;strong&gt;类型描述符&lt;/strong&gt;，在 go1.26 的源码里它叫 &lt;code&gt;abi.Type&lt;/code&gt;，
运行时内部沿用旧名 &lt;code&gt;_type&lt;/code&gt;。描述符被编进只读数据段，整个程序运行期间常驻不变。同一个类型
在一个程序里通常只有一份描述符，这一点后面判断「类型是否相同」时会用到。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;13
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;14
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;15
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;16
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#008000"&gt;// abi.Type：一个类型在运行时的表示（裁剪后的速写）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;type&lt;/span&gt; Type &lt;span style="color:#00f"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Size_ &lt;span style="color:#2b91af"&gt;uintptr&lt;/span&gt; &lt;span style="color:#008000"&gt;// 该类型一个值占多少字节，分配与拷贝都要它&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PtrBytes &lt;span style="color:#2b91af"&gt;uintptr&lt;/span&gt; &lt;span style="color:#008000"&gt;// 值的前若干字节里可能含指针，GC 只需扫到这里&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hash &lt;span style="color:#2b91af"&gt;uint32&lt;/span&gt; &lt;span style="color:#008000"&gt;// 类型的哈希，类型 switch、接口表查找时避免重算&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TFlag TFlag &lt;span style="color:#008000"&gt;// 标志位：是否具名、是否带 UncommonType、GC 位图是否按需生成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Align_ &lt;span style="color:#2b91af"&gt;uint8&lt;/span&gt; &lt;span style="color:#008000"&gt;// 该类型变量的对齐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FieldAlign_ &lt;span style="color:#2b91af"&gt;uint8&lt;/span&gt; &lt;span style="color:#008000"&gt;// 作为结构体字段时的对齐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Kind_ Kind &lt;span style="color:#008000"&gt;// 种类：int、struct、slice、chan… 决定如何解释这块内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000"&gt;// 比较该类型两个值是否相等：(指向 A, 指向 B) -&amp;gt; ==?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000"&gt;// 编译器按类型结构合成，map、接口比较、== 运算都落到它身上&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Equal &lt;span style="color:#00f"&gt;func&lt;/span&gt;(unsafe.Pointer, unsafe.Pointer) &lt;span style="color:#2b91af"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#008000"&gt;// GC 指针位图：标出该类型哪些字（word）是指针，精确 GC 据此扫描&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; GCData *&lt;span style="color:#2b91af"&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Str NameOff &lt;span style="color:#008000"&gt;// 类型名在名字表里的偏移（按需解出可读名字）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PtrToThis TypeOff &lt;span style="color:#008000"&gt;// 指向「*T」描述符的偏移，构造指针类型时复用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;Size_&lt;/code&gt; 是分配器（&lt;a href="../../part4memory/ch12alloc"&gt;12&lt;/a&gt;）
和值拷贝的依据。&lt;code&gt;Kind_&lt;/code&gt; 是一个枚举，告诉运行时「这块内存按哪种类型解释」，它的取值是有限的
二十余种基础种类：&lt;/p&gt;</description></item><item><title>4.2 接口</title><link>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/interface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/interface/</guid><description>&lt;h1 id="42-接口"&gt;4.2 接口&lt;/h1&gt;
&lt;p&gt;接口是 Go 类型系统的灵魂。它让「行为」与「实现」解耦，又用一种与众不同的方式做这件事：
结构化、隐式的满足，区别于绝大多数主流语言。这一节看接口在运行时怎么表示、方法怎么动态
分发、类型断言怎么落地，以及这套设计放进多态的谱系里处在哪个位置。沿用前几节的做法，下文
给出的结构体都是&lt;strong&gt;裁剪后的速写&lt;/strong&gt;：只留与设计相关的字段，注释说明它为何存在。完整定义可对照
&lt;code&gt;runtime/runtime2.go&lt;/code&gt;、&lt;code&gt;internal/abi/iface.go&lt;/code&gt; 与 &lt;code&gt;runtime/iface.go&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="421-两种表示iface-与-eface"&gt;4.2.1 两种表示：iface 与 eface&lt;/h2&gt;
&lt;p&gt;接口值在运行时一律是&lt;strong&gt;两个字宽&lt;/strong&gt;，但分两种。带方法的接口（&lt;strong&gt;非空接口&lt;/strong&gt;）用 &lt;code&gt;iface&lt;/code&gt;：一个指向
&lt;code&gt;itab&lt;/code&gt; 的指针，加一个指向具体数据的指针。空接口 &lt;code&gt;interface{}&lt;/code&gt;（即 &lt;code&gt;any&lt;/code&gt;）用 &lt;code&gt;eface&lt;/code&gt;：一个指向
类型信息 &lt;code&gt;_type&lt;/code&gt; 的指针，加一个数据指针。空接口没有方法，不需要方法表，于是直接存类型即可，
省下一层间接：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#008000"&gt;// 非空接口：带方法，故需方法表 itab（速写）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;type&lt;/span&gt; iface &lt;span style="color:#00f"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tab *itab &lt;span style="color:#008000"&gt;// 接口类型 × 具体类型 的方法表（含动态类型与 Fun 表）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data unsafe.Pointer &lt;span style="color:#008000"&gt;// 指向具体值（大于一字或需取址时为堆/栈上副本的指针）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#008000"&gt;// 空接口 any：无方法，直接挂类型信息（速写）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;type&lt;/span&gt; eface &lt;span style="color:#00f"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _type *_type &lt;span style="color:#008000"&gt;// 具体值的动态类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data unsafe.Pointer
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;data&lt;/code&gt; 存的是指针而非值本身。把一个 &lt;code&gt;int&lt;/code&gt; 放进接口，运行时会把它装箱（boxing）到一处可寻址
的内存，再让 &lt;code&gt;data&lt;/code&gt; 指过去，这也是「接口会引入一次分配」这一性能直觉的来源。两字表示是理解
后续一切的地基：动态分发、类型断言、乃至下面的 nil 陷阱，都是它的直接推论。&lt;/p&gt;</description></item><item><title>4.3 类型别名</title><link>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/alias/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/alias/</guid><description>&lt;h1 id="43-类型别名"&gt;4.3 类型别名&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;type A = B&lt;/code&gt;（类型别名）与 &lt;code&gt;type A B&lt;/code&gt;（定义新类型）只差一个等号，语义却根本不同。前者只是
给一个已存在的类型取个新名字，后者会造出一个全新的、有独立标识的类型。这个区别看似细微，却
牵动着类型相等、方法集、可赋值性（&lt;a href=".././type"&gt;4.1&lt;/a&gt;）这一整套规则，也牵动着一个 Go 一贯关心的
工程问题：当一份代码不再由原作者维护、却仍要在不破坏兼容的前提下演化时，类型该如何在包之间
迁移。这一节先把别名与定义类型的语义讲清，再交代别名为何在 Go 1.9 被引入，最后看它在 Go 1.24
迎来的泛型能力。&lt;/p&gt;
&lt;h2 id="431-别名-vs-定义类型"&gt;4.3.1 别名 vs 定义类型&lt;/h2&gt;
&lt;p&gt;按语言规范，类型声明分两种形式：别名声明（alias declaration）与类型定义（type definition）。
二者的分界就是那个等号。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;type Celsius float64&lt;/code&gt; 是类型定义，它「创建出一个新的、不同的类型，与给定类型有相同的底层
类型与操作」。&lt;code&gt;Celsius&lt;/code&gt; 与 &lt;code&gt;float64&lt;/code&gt; 从此是两个不同的名义类型（&lt;a href=".././type"&gt;4.1&lt;/a&gt;）：各有自己的
标识，可以挂自己的方法，彼此之间不能直接赋值，只能显式转换。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;type byte = uint8&lt;/code&gt; 是别名声明，它只是「把一个标识符绑定到给定类型」。在该标识符的作用域内，
&lt;code&gt;byte&lt;/code&gt; 就「充当 uint8 的别名」，二者是&lt;strong&gt;同一个类型&lt;/strong&gt;的两个名字，完全可以互换。标准库里
&lt;code&gt;byte&lt;/code&gt;（&lt;code&gt;= uint8&lt;/code&gt;）、&lt;code&gt;rune&lt;/code&gt;（&lt;code&gt;= int32&lt;/code&gt;），以及 Go 1.18 起 &lt;code&gt;any&lt;/code&gt;（&lt;code&gt;= interface{}&lt;/code&gt;），正是这样
定义的预声明别名。&lt;/p&gt;
&lt;p&gt;别名与定义类型最容易混淆、也最能体现差别的地方，是&lt;strong&gt;方法集&lt;/strong&gt;。看一段会编译失败的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt; 9
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;10
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;11
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;12
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;import&lt;/span&gt; &lt;span style="color:#a31515"&gt;&amp;#34;bytes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;type&lt;/span&gt; AliasBuf = bytes.Buffer &lt;span style="color:#008000"&gt;// 别名：就是 bytes.Buffer 本身&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;type&lt;/span&gt; DefBuf bytes.Buffer &lt;span style="color:#008000"&gt;// 定义类型：底层相同，但方法集为空&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;func&lt;/span&gt; demo() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#00f"&gt;var&lt;/span&gt; a AliasBuf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	a.WriteString(&lt;span style="color:#a31515"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) &lt;span style="color:#008000"&gt;// OK：AliasBuf 与 bytes.Buffer 是同一类型，方法集完全相同&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#00f"&gt;var&lt;/span&gt; d DefBuf
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	d.WriteString(&lt;span style="color:#a31515"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;) &lt;span style="color:#008000"&gt;// 编译错误：DefBuf 未继承 bytes.Buffer 的任何方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	_ = bytes.Buffer(d) &lt;span style="color:#008000"&gt;// 但可显式转换回去：二者底层类型相同&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&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;DefBuf&lt;/code&gt; 与 &lt;code&gt;bytes.Buffer&lt;/code&gt; 底层类型相同，因此可以互相显式转换，但 &lt;code&gt;DefBuf&lt;/code&gt; 是一个&lt;strong&gt;新类型&lt;/strong&gt;，
它不继承 &lt;code&gt;bytes.Buffer&lt;/code&gt; 的方法集，&lt;code&gt;d.WriteString&lt;/code&gt; 找不到接收者。&lt;code&gt;AliasBuf&lt;/code&gt; 则压根不是新类型，
它&lt;strong&gt;就是&lt;/strong&gt; &lt;code&gt;bytes.Buffer&lt;/code&gt;，方法集自然一模一样。一句话：定义类型造出&lt;strong&gt;新东西&lt;/strong&gt;（新标识、空方法
集、需自行定义方法），别名只给旧东西&lt;strong&gt;取个新名&lt;/strong&gt;（同一标识、同一方法集）。&lt;/p&gt;</description></item><item><title>4.4 进一步阅读的参考文献</title><link>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/ref/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part2lang/ch04type/ref/</guid><description>&lt;h1 id="310-进一步阅读的参考文献"&gt;3.10 进一步阅读的参考文献&lt;/h1&gt;
&lt;table class="bib"&gt;
&lt;tr&gt;
&lt;td&gt;[Ghemawat and Menage, 2009]&lt;/td&gt;&lt;td&gt;Sanjay Ghemawat, Paul Menage. "TCMalloc : Thread-Caching Malloc." Google Inc., 2009 &lt;a href="http://goog-perftools.sourceforge.net/doc/tcmalloc.html"&gt;http://goog-perftools.sourceforge.net/doc/tcmalloc.html&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;</description></item></channel></rss>