Go 的语法、变量与数据类型 — 一套刻意做小的类型系统¶
这一章讲什么: Go 程序由哪些最小零件组成——包、变量、常量、十几种数据类型、 输入输出——以及每个零件设计时「删掉了什么」。 它在全书链条里的位置: 这是地基章。第 03 章在这堆零件之上讲「怎么把它们组织成 模块」,第 04 章讲「出错怎么办」;后面所有章节(API、数据库、并发流水线)都默认你 已经会这里的每一个零件。 读法: 如果你学过别的语言,别跳——Go 在每个看似熟悉的地方都藏了一个有意的 「不一样」,本章每一节的「解决什么问题」就是在讲这个不一样。
1. 顶层全景:一个程序的最小骨架¶
原书给的最小 Go 程序只有三行(第 01 章也出现过的那个):
这三行对应三件不可少的事,后面所有 Go 代码都是它们的展开:
| 零件 | 作用 | 本章哪节展开 |
|---|---|---|
package main |
声明这个文件属于哪个包;main 这个包名特指「可执行程序」 |
§2 |
import "fmt" |
引入别人的代码给自己用 | §2 |
func main() |
程序入口,从这里开始执行 | 第 03 章细讲函数 |
主线例子(贯穿本章): 一个「用户注册」小程序。它读入一行用户名和年龄, 存进一条用户记录,再打印一份统计。每一步都用本章一个机制:
这个例子是我们顺着原书各节的示例拼起来的(原书各机制分开举例,没有这样一个完整程序); 每个机制的原书出处都在脚注里。
2. 包、import 与 gofmt:先统一格式,再谈风格¶
2.1 包是什么¶
Go 把代码组织成包(package):每个 .go 文件第一行必须声明自己属于哪个包,
一组同包的文件一起编译1。包有两个作用:一是分工——网络代码一个包、加密代码一个包;
二是复用——标准库就是一群官方包,import "net/http" 一行就把整个 HTTP 包的能力
拿过来2。
import 可以单写,也可以分组:
原书强调这带来一个文化后果:Go 项目靠包天然分层,大型代码库因此「clear modularization」3。
2.2 gofmt:不让任何人讨论格式¶
解决什么问题: 别的语言里,「大括号换不换行」「用 Tab 还是空格」能吵十年, 代码评审一半时间在吵格式。
Go 的做法: 官方工具 gofmt 把格式定死并自动执行:大括号必须和控制语句同一行、
缩进必须用 Tab、行尾分号由编译器自动补——你基本见不到也无需写分号4。
它不是建议,是事实标准:编辑器存盘时自动跑一遍,所有人的代码长得一样。
为什么有效: 格式的「选择权」被没收,换来读陌生人代码时零适应成本。 这一条和第 01 章「标准库厚」是同一个哲学:能统一的不留给个人发挥。
2.3 控制流:三样,没有更多¶
Go 的全部控制流是三样:if、for、switch——原书明确说 Go 「trims away unnecessary
complexity」,循环只有 for 一种5:
if value > 10 {
fmt.Println("Large value")
}
for i := 0; i < 5; i++ {
fmt.Println(i)
}
switch day {
case "Monday":
fmt.Println("Start of week")
default:
fmt.Println("Midweek or weekend")
}
两个有意的「不一样」:
if的条件不带括号。这不是偷懒,是 gofmt 规定的统一写法。switch默认不会贯穿到下一个 case(C 语言会的那个坑被默认关掉了;真想贯穿要写fallthrough关键字)5。
3. 变量与常量:两种声明,三个坑¶
3.1 两种声明法¶
Go 给变量两种写法,原书并列给出6:
注意 var count int 里类型写在变量名后面——Go 的惯例和 C 相反。简写 := 只能在
函数内部用,函数外面必须用 var7。
主线例子第 ① 步: 注册程序开头:
3.2 常量与它的两个变种¶
常量用 const 声明,值必须在编译时就能确定——运行时才算得出来的东西
(比如函数调用的结果)不能当常量7。Go 还细分:
- 带类型常量:
const limit int = 100,类型钉死,参与运算时被检查; - 无类型常量:
const limit = 100,编译器按使用场合灵活解释——用在浮点运算里就当浮点。
原书说这种双轨让常量「既 predictable 又 convenient」8。
3.3 三个坑(原书明列)¶
:=不能用在包级(函数外),新手常在这里摔7;- 运行期产生的值不能赋给常量7;
- 声明了不用的变量是编译错误——不是警告,是直接编译不过7。 这一条最反直觉也最有用:它强制你删掉写歪了的草稿,垃圾不会留到代码库里。
4. 基本类型:数字、布尔、字符串¶
4.1 数字类型:一张按位宽分的表¶
Go 的数字类型按「占多少位、带不带符号」命名,原书照规范给了完整表9:
| 类型 | 范围 | 什么时候用 |
|---|---|---|
int8 / uint8 |
−128…127 / 0…255 | 明确知道数值很小 |
int32 / uint32 |
约 ±21 亿 / 0…约 42 亿 | 与文件格式、网络协议对齐时 |
int64 / uint64 |
约 ±92 亿亿 | 时间戳、大计数 |
float32 / float64 |
IEEE 754 浮点 | 小数;float64 是默认 |
byte |
uint8 的别名 |
原始字节 |
rune |
int32 的别名 |
一个 Unicode 字符(Unicode:给全世界每个字符统一编号的国际标准) |
int / uint |
32 或 64 位,看机器 | 日常默认 |
两个别名要记住:byte 就是 uint8,rune 就是 int32——看见别人的代码里写
rune 不要陌生9。int 的大小随机器变(32 位机器上 32 位、64 位机器上 64 位),
做可移植计算时要注意——这是其他语言用户容易默认错的一点。
主线例子第 ⑥ 步用到的细节: 年龄用 int,余额类小数用 float64——
不能用 int 存小数,那会把 0.1 直接变成 0(原书在 AI 建议一节拿这个当反面例子10)。
4.2 布尔¶
bool,两个值 true / false,没有别的真值(不能把 0 或 1 当布尔用)9。
4.3 字符串:不可改的字节序列¶
字节(byte)是 8 个二进制位组成的一个 0–255 的整数,文件、网络数据最原始的形态;序列就是排成一队。Go 的 string 是一串字节,不可变——「once they are generated, their contents
cannot be altered」11。两个直接后果:
len(s)返回的是字节数,不是字符数:"你好"的len是 6(每个汉字 3 字节), 不是 2;- 想「改」字符串只能造一个新的。配合
[]byte(s)可以转成字节切片改完再转回来12。
5. 复合类型:从数组到 channel¶
这一节是全章重心,七种复合类型每种回答「解决什么存取问题」。
5.1 数组:定长, rarely 直接用¶
数组是定长的同类型序列,长度是类型的一部分:
「长度是类型的一部分」意味着 [3]int 和 [5]int 是两种不同的类型,不能互换。
实际开发里数组几乎总被下面的切片取代;数组还留着一个重要规则:不能直接嵌套自己
([10]T1 里装 T1 是非法的,装 *T1 指针才合法——指针就是「存另一个值的地址」的变量,§5.5 专讲——结构里不能有无限大的自己)13。
5.2 切片:数组的「窗口」,Go 里真正的主角¶
解决什么问题: 数组定长太死——读一个文件,行数事先不知道,数组装不下。
切片(slice)是「指向某段底层数组的窗口」:它记三件事——从哪开始、多长、
底层数组容量多大。所以切片可以变长(用 append 追加),可以互相重叠地
看同一段数据14。创建方式:
原书给了一个精确等价:make([]int, 50, 100) 就是 new([100]int)[0:50]——
先造一个 100 的数组,再取前 50 个当窗口15。注意「共享存储」:两个切片若看着
同一个底层数组,通过一个改,另一个也看得见;独立的数组之间则互不影响14。
这是 Go 新手最常踩的坑之一,第 04 章的调试工具能帮上忙。
主线例子第 ④ 步: 所有注册用户的名字存进切片,随时 append。
5.3 结构体:把几个字段捆成一条记录¶
结构体(struct)是有名字段的集合,Go 里「对象」的替代物(没有类,第 03 章细说):
原书还讲了嵌入字段(embedded field):只写类型名不写字段名,那个类型的字段和 方法会被「提升」到外层——这是 Go 实现组合(而非继承)的手法,第 03 章细讲16。
主线例子第 ② 步: 每个注册用户就是一条 User 记录。
5.4 map:按 key 查的字典¶
map 是无序的 key→value 集合,map[string]int 读作「字符串 key、整数值」:
对 map 取值有两个返回值的写法 age, ok := ages["alice"]——ok 告诉你这个 key
在不在(不在时 age 是该类型的零值 0,光看值分不出「没这个人」和「这个人 0 岁」)。
两个坑(原书明写):key 的类型必须支持 == 比较——函数、map、切片不能当 key;
nil map 不能写入——只声明 var m map[string]int 就 m["x"]=1 会 panic
(运行时崩溃),必须先 make17。
主线例子第 ③ 步: 用 map[string]User 按名字查用户。
5.5 指针:地址,不是魔法¶
指针(pointer)存的是另一个值的地址。Go 保留了指针但砍掉了指针算术:
什么时候用:函数想改调用者的变量(传地址而不是复制一份),或者大结构体想避免
整份拷贝。没初始化的指针是 nil,解引用 nil 会 panic——这是第 04 章的主角之一18。
5.6 函数类型与接口:行为也是类型¶
函数类型把「签名一致的函数」归为一类,变量可以存函数、函数可以当参数传19。 这听着抽象,第 07 章的中间件全靠它。
接口(interface)是「方法清单」:一个类型只要实现了清单上的全部方法,就自动满足 这个接口,不需要显式声明「我实现了」(这叫隐式实现)20:
接口三种形态,原书按从简到繁排:
| 形态 | 是什么 | 例子 |
|---|---|---|
| 基本接口 | 只有方法清单 | interface{ String() string } |
| 嵌入接口 | 把已有接口并进来 | ReadWriter = Reader + Writer |
| 广义接口 | 能用 \| 列出具体类型,还能写 ~int 表示「底层类型是 int 的都算」 |
泛型约束,第 03 章一带而过 |
空接口 interface{}(Go 1.18 起有个更好读的别名 any)表示「任何类型」——
它能装一切,但取出来要做类型断言,否则没法用21。
接口的零值是 nil——一个 nil 接口调用方法会 panic,这条第 04 章展开。
5.7 channel 类型:连类型都带方向¶
channel 本身也是一种类型,而且能声明方向:
方向是编译期检查的:把一个「只能收」的 channel 传给要「发」的函数,编译直接报错。
这个设计让函数签名自带「我只会往这个 channel 里放数据」的合同,读代码的人不用猜22。
channel 是第 05 章的主角,这里记住两件事:它由 make 创建,可带缓冲容量;
close 关闭后,接收方用 v, ok := <-ch 能收到「已关闭」的信号(ok 为 false)22。
5.8 七种复合类型,一张选型总表¶
学完之后回头看,这七种的区分标准就三个:定长还是变长、按位置还是按键找、 能不能并发安全地共享。对着主线例子的四个用场:
| 需求 | 选 | 一句话理由 |
|---|---|---|
| 名字列表,越注册越多 | slice |
变长,append 就行 |
| 按名字查整条记录 | map |
按键找,O(1) |
| 一条记录本身 | struct |
字段有名字、有类型 |
| 函数想改调用者的变量 | 传指针 *T |
值传递改不了外面 |
| 函数当参数/返回值 | 函数类型 | 行为也是值 |
| 「任何类型都收」 | any |
空接口,取出再断言 |
| goroutine 之间传 | channel |
传送带,带方向 |
三个回头看的提醒:
- 数组在这个表里没有位置——不是它没用,而是它的活(定长缓冲、协议头) 要到第 05、08 章才显形;日常数据容器就是切片;
map和slice都不要提前担心并发——第 05 章会说,默认它们都不安全, 要么走 channel,要么加锁;- 选
struct还是map的判断很简单:字段是固定的就 struct(编译器帮你检查 拼写),字段是动态的就 map(运行时再查)。
5.9 广义接口:type set(类型集)是怎么算的¶
第 02 章给过广义接口的式子(int | ~int 那种),这里把规则算一遍,
因为这是 Go 泛型的门槛,也是「接口」这个词最不像 Java 接口的地方。
类型集的含义:一个接口「能装哪些类型」的集合。逐条规则(原书照规范列了七条, 收成三句):
- 写一个具体类型(如
int)——集合里只有它自己; - 写
~int——集合里是「底层类型是 int 的所有类型」(int自己,以及type MyInt int这种自定义类型); - 用
|并列几项——取并集;交集为空就是空集(如int | string再加方法 约束,没有类型同时满足,编译直接拒绝)。
例子(演示):
interface { ~int } // 底层是 int 的都算:MyInt 也算
interface { int } // 只有 int:MyInt 都不算
interface { ~int; String() string } // 底层是 int、且带 String 方法的
any 是空接口的别名(第 02 章),它的类型集是全部非接口类型——所以
any 能装一切,也正因如此,从 any 里取东西必须类型断言
(「我断言这个 any 里装的是 string」,断言错了运行期 panic)。
这条链决定了 Go 泛型函数的样子:约束写接口,函数体里对这个类型集能做的事
就只有约束里声明的那些——类型集是泛型的合同。
5.10 结构体嵌入:方法「提升」的边界¶
嵌入字段(只写类型名不写字段名)带来的「提升」规则,原书按规范给了边界:
- 外层结构体直接「拥有」内嵌类型的字段和方法,调用
x.f时编译器自动展开成x.T.f; - 提升只跨一层规则清晰、多层同名会有歧义:两个内嵌类型都有方法
Close时, 外层调x.Close()编译报错,必须写全x.A.Close()——歧义是编译期错误,不是 运行期惊喜; - 内嵌 接口 也合法:结构体嵌入
io.Reader,自己就实现了Read—— 这是组合模式在 Go 里的标准写法(第 07 章的 ResponseWriter 包装就用它)。
6. 零值、类型推导与转换:Go 的「默认值」哲学¶
6.1 零值:不初始化也有确定的值¶
Go 没有「未初始化的随机值」。任何变量没给初值,就自动拿到它类型的零值23:
| 类型 | 零值 |
|---|---|
| 数字 | 0 |
| 布尔 | false |
| 字符串 | ""(空串) |
| 指针、接口、切片、map、channel、函数 | nil |
nil 大致是「什么都没指向」的标记。这张表要背下来的一半原因是:nil 检查
在 Go 代码里无处不在(「这个 map 是不是 nil」「这个接口是不是 nil」),
另一半原因是零值设计让很多初始化代码可以直接省掉。
6.2 类型推导与「不做隐式转换」¶
:= 让编译器从右边推类型:total := 42 是 int,ratio := 3.14 是 float6424。
但推导只发生一次——声明之后,Go 绝不做隐式类型转换:
把 int 直接赋给 float64 变量是编译错误,哪怕「明明装得下」25。
这和其他语言(尤其 Python 和 C)相反:那边默默帮你转,转错了运行时才炸;
Go 逼你当场写清,换来「行为总是 explicit and predictable」25。
string 和 []byte 互转也要显式:b := []byte(s)25。
主线例子第 ⑤ 步: 打印统计时,总人数 len(names) 是 int,
若要拼进浮点算平均,得先 float64(len(names))。
7. 输入输出:fmt 求方便,bufio 求快¶
7.1 fmt:打印与简单读入¶
fmt.Println输出并换行;fmt.Printf用格式动词拼串:%d整数、%s字符串、%f浮点、%v「任何值按默认样子打」、%t布尔26;- 读入:
fmt.Scanln(&name)读一行——注意参数要传地址&name, 因为函数要往里写。Scan 系适合「问用户一个问题」,不适合大批量数据27。
7.2 bufio:批量与逐行¶
bufio 在底层读取器外面包一层缓冲,攒一批再读写,系统调用次数大减28:
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
fmt.Println("Received:", line)
}
Scanner 默认按行切,也能换成按词切(bufio.ScanWords)或自定义切法——
读日志、读配置、做命令行交互都用它。写侧对应 bufio.Writer,写完要调
Flush() 把缓冲区里的内容真正推出去28。
原书给了一张选择表,值得直接记住29:
| 需求 | 用 |
|---|---|
| 快速打印、调试用 | fmt.Println |
| 结构化输出 | fmt.Printf |
| 简单用户输入 | fmt.Scan* |
| 高性能读写 | bufio.Reader / bufio.Writer |
| 逐行文本处理 | bufio.Scanner |
主线例子第 ① 步的读入因此选 bufio.Scanner 而不是 fmt.Scanln——
注册程序要逐行处理输入。
8. AI 辅助写类型(辅线)¶
原书在本章末尾给了一组「让 AI 干这类活」的用法30:
- 生成声明: 打「创建一个存用户年龄的整型变量,初值 18」,得
age := 18; - 类型建议: 给它看数据结构描述,它建议
float64还是struct; - 零值利用: 让它写「默认值安全」的声明;
- 一致性重构: 把多个单行
var合成组、建议:=、揪出未使用变量。
本书的立场(第 01 章已定):这些是省键盘的活,判断选型的责任仍在人——
AI 不会替你想「年龄该用 int 还是 uint8」,它只会给你最常见答案。
反过来,让 AI 解释一段含切片的代码「这两个变量是不是看着同一个数组」,
是很好的自学用法(它答完你再对着 §5.2 核对)。
9. 作者的判断与证据¶
是语言事实的(可对照官方规范验证):
- 零值表、显式转换、nil map 写入 panic、
int位数随机器——这些是 Go 规范定义的行为, 原书的表述与 go.dev/ref/spec 一致(原书多处注明「Source: go.dev/ref/spec」)92325。 - 复合类型自嵌套限制、接口类型集规则——直接引自规范13。
是作者观点的:
- 「格式化减少认知负荷」「三样控制流足够」——设计哲学叙述,无法证伪但对读代码确实有效;
- 本章 AI 一节通篇是「可以怎么用来提效」,没有给对照数据;「avoid subtle bugs caused by inappropriate type choices」这类收益是合理推测,不是测量结论10。
判断(我们的,不是书里的): 这一章把规范内容嚼碎讲,适合零基础; 但对有经验的开发者,最有价值的是那三处「有意的不同」——声明不用会编译错、 不做隐式转换、nil map 写入 panic。它们全是「把一类运行期错误挪成编译期或显式失败」, 这是 Go 可靠性的真正来源,比「简单」这个形容词具体得多。 如果错,会错在: 若把「Go 强制显式」读成「Go 不会类型错」就错了—— 接口 nil、类型断言失败、切片共享,都还是运行期坑,第 04 章正为此存在。
10. 边界与局限¶
- 本章教「有哪些零件」,不教「怎么组合」——组合是第 03 章(函数与包)以后的事。
- 泛型几乎没展开: 广义接口只按规范介绍一遍,没有「什么时候该写泛型函数」的实战指导。
- 例子以语法演示为主,离真实系统有距离;读者要自己完成「从练习题到项目」的跨越(第 06–08 章补)。
- 性能一笔带过(bufio 为什么快只有一段),第 08 章的 pprof 和第 10 章的性能调优才补上。
11. 可带走的¶
- 程序三骨架:
package main+import+func main();包是编译与分工的单位。 var与:=两种声明;:=仅限函数内;不用的变量编译不过。- 常量编译期定值,分带类型/无类型;运行期的值当不了常量。
- 数字按位宽命名,
byte=uint8、rune=int32;int位数随机器;小数用float64。 - 字符串是字节序列、不可变,
len数的是字节。 - 数组定长且长度是类型;切片是窗口、可 append、多切片可共享底层数组。
- nil map 不能写;取 map 用
v, ok双返回值。 - 零值表:数字 0、布尔 false、字符串 ""、其余 nil。
- 不做隐式转换:
int→float64必须写float64(x)。 - 输出 fmt、批量 bufio;按原书的选择表挑。
- channel 类型带方向(
chan<-只发、<-chan只收),方向错编译期就拦。 - 接口是方法清单、隐式实现;
any是空接口别名。
12. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 包与 import | 2. Go Syntax, Variables, and Data Types | text/12-ch02-2-go-syntax-variables-and-data-types.txt:75(搜「Packages and Imports」) |
| gofmt 四条规则 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:91(搜「Formatting Philosophy」) |
| 三样控制流 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:105(搜「Control Structures and Flow」) |
| 两种变量声明 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:128(搜「Variables and Constants」) |
| 三个坑 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:153(搜「Common Pitfalls」) |
| 数字类型表 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:170(搜「Numeric Types」) |
| 字符串不可变 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:218(搜「immutable」) |
| 数组与自嵌套限制 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:231(搜「Array Types」) |
| 切片与 make 等价式 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:271(搜「Slice Types」)text/12-ch02-2-go-syntax-variables-and-data-types.txt:291(搜「make([]int, 50, 100)」) |
| 结构体与嵌入字段 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:299(搜「Struct Types」) |
| map 与 nil map | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:354(搜「Map Types」) |
| 指针 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:382(搜「Pointer Types」) |
| 接口三形态 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:418(搜「Interface Types」)、:467(搜「Embedded Interfaces」)、:499(搜「General Interfaces」) |
| any 别名 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:559(搜「alias for interface{}」) |
| channel 类型与方向 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:564(搜「Channel Types」) |
| 零值表 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:616(搜「Zero Values」) |
| 显式类型转换 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:631(搜「Type Conversion」) |
| fmt 与 bufio | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:646(搜「fmt and bufio」) |
| 包选择表 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:724(搜「Choosing between fmt and bufio」) |
| AI 辅助生成声明 | 同上 | text/12-ch02-2-go-syntax-variables-and-data-types.txt:740(搜「AI-Assisted Code Generation」) |
-
出处:「2. Go Syntax, Variables, and Data Types」第 75 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:75,搜「Packages and Imports」)。原文:「Each Go file is a part of a package, which aids in organizing similar features.」 ↩ -
出处:同章第 80 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:80,搜「import keyword」)。示例import "net/http"见同段。 ↩ -
出处:同章第 89 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:89,搜「clear modularization」)。 ↩ -
出处:同章第 91–101 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:92,搜「strict opinion on formatting」;text/12-ch02-2-go-syntax-variables-and-data-types.txt:97,搜「Mandatory curly braces」)。四条规则:大括号同行、Tab、自动分号、统一空白。 ↩ -
出处:同章第 105–124 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:107,搜「three primary constructs」;text/12-ch02-2-go-syntax-variables-and-data-types.txt:110,搜「fall through」)。三个例子在同段。 ↩↩ -
出处:同章第 135–143 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:135,搜「two primary forms」)。 ↩ -
出处:同章第 153–159 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:153,搜「Common Pitfalls」)。三个坑逐条列于原文。 ↩↩↩↩↩ -
出处:同章第 145–152 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:145,搜「Typed and Untyped Constants」)。 ↩ -
出处:同章第 170–213 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:170,搜「Numeric Types」;别名见 :199,搜「alias for uint8」)。 ↩↩↩↩ -
出处:同章第 763–776 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:764,搜「recommending the most appropriate data type」;「using int instead of float64」见 :775)。 ↩↩ -
出处:同章第 215–220 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:217,搜「series of bytes」;不可变见 :218,搜「immutable」)。 ↩ -
出处:同章第 637–640 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:637,搜「conversions between byte slices」)。 ↩ -
出处:同章第 247–268 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:248,搜「may not directly or indirectly contain」)。「Source: go.dev/ref/spec」为原书自注。 ↩↩ -
出处:同章第 271–282 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:279,搜「underlying array」;共享存储见 :281,搜「shares storage」)。 ↩↩ -
出处:同章第 289–292 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:283,搜「make, which takes a slice type」)。等价式make([]int, 50, 100)与new([100]int)[0:50]见同段。 ↩ -
出处:同章第 317–330 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:317,搜「embedded field」;提升规则见 :329,搜「promoted」)。 ↩ -
出处:同章第 354–380 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:361,搜「comparison operators」;nil map 见text/12-ch02-2-go-syntax-variables-and-data-types.txt:380,搜「none of the elements can be appended」)。 ↩ -
出处:同章第 382–386 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:382,搜「Pointer Types」;「An uninitialized pointer holds a value of null」)。 ↩ -
出处:同章第 389–416 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:389,搜「Function Types」)。 ↩ -
出处:同章第 418–465 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:419,搜「delineates a group of types」;Locker 例见 :462,搜「Locker」)。 ↩ -
出处:同章第 559–562 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:559,搜「alias for interface{}」)。 ↩ -
出处:同章第 564–597 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:570,搜「The optional <- operator」;make 与 close 见text/12-ch02-2-go-syntax-variables-and-data-types.txt:586,搜「make(chan int, 10)」)。 ↩↩ -
出处:同章第 616–629 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:618,搜「automatically initialized to zero」)。零值表见 :620–624。 ↩↩ -
出处:同章第 605–614 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:606,搜「inferring types」)。三个推导例子见同段。 ↩ -
出处:同章第 632–644 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:632,搜「requires explicit type conversion」;「compile-time error」见 :641)。 ↩↩↩↩ -
出处:同章第 656–671 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:656,搜「Formatted Output」;动词表见 :670,搜「%s」)。 ↩ -
出处:同章第 673–681 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:674,搜「Scan, Scanln」)。 ↩ -
出处:同章第 683–722 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:683,搜「Efficient Input」;Flush 见 :708,搜「Flush」)。 ↩↩ -
出处:同章第 724–734 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:724,搜「Choosing between fmt and bufio」)。表 2.3 见同段。 ↩ -
出处:同章第 740–818 段(
text/12-ch02-2-go-syntax-variables-and-data-types.txt:740,搜「AI-Assisted Code Generation for Data Types」;自然语言例子见 :754,搜「user's age」)。 ↩