前言
本专栏是笔者在学习《Go程序设计语言》这本书时,对每个章节认为较为重要(容易忘记👻)的知识点记录的笔记,其中也会有少量的思考👀, 现整理成博客分享出来。
如果对专栏感兴趣,跑过去看一眼,书中的每一章都有:《Go程序设计语言》笔记
❗️注意❗️:本专栏不是详细的知识讲解,只是碎片的知识条目,或可作为Go知识点查漏补缺的小工具~
数组
- 数组具有固定长度,声明:
var a [4]int
;很少直接使用数组,一般都用slice
; - 声明时自动初始化长度:
var a [...]int{1,2,3}
,自动初始化长度为3
; - 数组长度必须在编译时确定;
- 声明并初始化数组时,可以提供给定位置上的元素值:
var a [...]int{1:23, 2:34}
; crypto/sha256.Sum256()
可以计算[]byte
的SHA256
摘要;
slice
slice
有三个属性:指针,长度,容量;容量大小通常是从slice
其实元素,到底层数组的最后一个元素之间的元素个数;- 指针指向第一个可从
slice
中访问的元素,但它并不一定是数组的第一个元素; - 可以使用
len cap
分别获取slice
的长度、容量; - 和数组不同的是,
slice
无法作比较,因此不能用==
来测试两个slice
是否拥有相同元素;对于[]byte
可以使用bytes.Equal
来比较;slice
有可能包含它自身;slice
的元素在生命周期内可能变化,而散列表仅对元素做浅拷贝,所以不能作为map
的键;
slice
唯一允许的是和nil
作比较;相等时,slice
的长度和容量都是0
;- 可以使用
make([]T, len, cap)
创建一个slice
;使用copy
函数复制元素,返回复制的元素个数,是两个slice
长度的较小值; - 可以使用
append
函数来追加元素,在需要时会扩展一倍容量,以减小内存分配次数,将原slice
数据复制到其中,再返回新的slice
;一般会将调用结果赋值给传入的slice
:sli = append(sli, x)
; - 对于任何函数,只要有可能改变
slice
的长度或容量,或使之指向不同数组,都应该更新slice
变量;
map
map
中的键必须是可以通过==
来比较的数据类型,所以slice
不可以作为键;- 使用
make(map[KeyType]ValueType)
来声明一个map
; - 使用内置函数
delete
来移除元素;即使没有传入的键对应的值也是安全的; - 无法获取map元素的地址,因为随着
map
的增长可能导致已有元素被重新散列到新的存储位置,使得地址无效; - 使用
for k, v := range mymap
来迭代获取键值对,但迭代顺序是不固定的; - 向
nil
的map
中添加元素会导致宕机; - 无论
map
是否有键k
对应的值,都能获取到值,可以通过额外返回bool
值确定:v, ok:= mymap[k]
; map
与slice
一样,只能和nil
比较;
结构体
- 结构体变量或者结构体指针均采用
.
访问成员; - 成员变量的顺序不同,是不同的结构体;但一般只关注变量的组合;
- 如果成员变量名称首字母是大写的,则该变量是可导出的;
- 结构体不能嵌套自身的变量,但可以嵌套自身的指针;由此可以实现链表等数据结构;
- 空结构体
struct{}
没有长度,不携带任何信息,可替代map
中的bool
值,但尽量避免这样用:节约内存很少且语法复杂; - 字面量初始化:
var p Point{100, 200}
或var p Point{x: 100, y:200}
;但二者不可混用; - 如果变量是不可导出的,则在其它包中,也不能通过隐式初始化该变量;
- 结构体变量形参是值引用,想修改或者提高效率,使用指针变量;
- 快速创建一个结构体指针:
pp := &Point{100, 200}
; - 如果所有成员都是可比较的,那两个结构体变量可以使用
==
或!=
来比较;并且此时可以作为map
的键; - 使用匿名成员避免类嵌套带来访问上的很多
.
点运算符,匿名成员只用声明类型,而不用给变量名称;所以也同一类型只能有一个匿名成员; %#v
可以输出变量名称;
JSON
encoding/json
包提供JSON
的序列化与反序列化:Marshal() MarshalIndent() Unmarshal()
;- 只有可导出的成员才能序列化为
JSON
; - 使用标签来指定序列化的键名称:Position Point
json:pos
;标签可指定多个,用空格分开;
文本和HTML模板
-
html/template
和text/template
提供一种机制:将程序变量的值代入到文本或者HTML
模板中; -
模板中包含一个或多个双大括号包围的单元:
{{...}}
,这称为操作;它是一个表达式,可以选择结构体成员、调用函数和方法、逻辑控制、循环等等; -
操作中的
|
会将前一个操作的结果当做下一个操作的输入; -
使用
report := template.New("name").Funcs(template.FuncMap{"daysAgo": daysAgo}.Parse(templ))
来创建模板,使用report.Execute(os.Stdout, data)
来输出模板; -
在模板中访问变量:
{{.X}}
,在传入的data
数据中需要有X
成员,且是可导出的;否则操作不起作用; -
html1/template
中对于HTML/JS/CSS/URL
中的字符串进行自动转义,一次来避免一些安全问题,如注入攻击; -
可以使用
template.HTML
类型,其中的字符串不会被自动转义,是受信任的字符串类型; -
模板中可以:
- 声明变量:
{{$var := .Name}}
; - 索引:
{{$var := index .Foodlist i}}
- 循环:
{{range .Foodlist}} ...{{else}} {{end}}
,在...
部分,使用{{.}}
来访问每个元素; - 传递结果:
{{x | prirntf %v }}
,会将x
放在%v
后面;
- 声明变量:
如有错误 ❌ ,欢迎指正 ☝️~
如有收获 🍗,可以考虑点赞👍/评论💬/收藏⭐️/关注👀,大家共同进步~