- 默认情况下,数组的每个元素都被初始化为元素类型对应的零值
- 如果在数组的长度位置出现的是“…”省略号,则表示数组的长度是根据初始化值的个数来计算
- 数组的长度是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数组类型
- 定义了一个含有100个元素的数组r,最后一个元素被初始化为-1,其它元素都是用0初始化。
r := [...]int{99: -1}
- 如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,支持
==
和!=
- 当调用一个函数的时候,函数的每个调用参数将会被赋值给函数内部的参数变量,所以函数参数变量接收的是一个复制的副本,并不是原始调用的变量。
- 数组依然很少用作函数参数;相反,我们一般使用slice来替代数组。
Slice#
- 一个slice由三个部分构成:指针、长度和容量
- 内置的len和cap函数分别返回slice的长度和容量。
- 多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠
- x[m:n]切片操作对于字符串则生成一个新字符串,如果x是[]byte的话则生成一个新的[]byte。
- slice将允许在函数内部修改底层数组的元素
- slice之间不能比较,因此我们不能使用==操作符来判断两个slice是否含有全部相等元素
- 标准库提供了高度优化的bytes.Equal函数来判断两个字节型slice是否相等([]byte),但是对于其他类型的slice,我们必须自己展开每个元素进行比较
Map#
- 它是一个无序的key/value对的集合
- 在Go语言中,一个map就是一个哈希表的引用
- key必须是支持==比较运算符的数据类型
- 不建议将浮点数作为key值
- 创建map的几种方法:
1
2
3
4
5
6
7
8
|
ages := make(map[string]int)
ages = map[string]int{
"cat": 321,
"dog": 123
}
ages = map[string]int{}
|
- 删除:
delete(ages, "cat")
- map中的元素并不是一个变量,所以不能进行取地址操作
&
。原因是扩容导致地址失效
- Map的迭代顺序是不确定的
- 判断元素是否存在于map中的写法
1
2
3
|
if cat, ok := ages["cat"]; !ok{
// do something
}
|
- go语言没有实现
set
- 将slice设置为map的key的方法(将slice转字符串)
1
2
3
4
5
6
|
var m = make(map[string]int)
func k(list []string) string { return fmt.Sprintf("%q", list) }
func Add(list []string) { m[k(list)]++ }
func Count(list []string) int { return m[k(list)] }
|
结构体#
- 可以对对成员取地址,然后通过指针访问
- 结构体成员的顺序有影响(不同顺序但同样成员的结构体不算同一个结构体)
- 如果结构体没有任何成员的话就是空结构体,写作struct{}。它的大小为0,也不包含任何信息,但是有时候依然是有价值的,如用map实现set
1
2
3
4
5
6
|
seen := make(map[string]struct{}) // set of strings
// ...
if _, ok := seen[s]; !ok {
seen[s] = struct{}{}
// ...first time seeing s...
}
|
1
2
|
type T struct{ a, b int }
var _ = T{a:1, b:2}
|
- 如果考虑效率的话,较大的结构体通常会用指针的方式传入和返回
- 如果要在函数内部修改结构体成员的话,用指针传入是必须的;因为在Go语言中,所有的函数参数都是值拷贝传入的,函数参数将不再是函数调用时的原始变量
- 如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的
- 结构体的匿名成员
1
2
3
4
|
type Circle struct {
Point
Radius int
}
|
- 得益于匿名嵌入的特性,我们可以直接访问叶子属性而不需要给出完整的路径
1
2
3
4
5
|
var w Wheel
w.X = 8 // equivalent to w.Circle.Point.X = 8
w.Y = 8 // equivalent to w.Circle.Point.Y = 8
w.Radius = 5 // equivalent to w.Circle.Radius = 5
w.Spokes = 20
|
JSON#
go标准库提供了go内置类型和json的相互转换功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package main
import (
"encoding/json"
"fmt"
)
type Movie struct{
Title string
Year int `json:"released"`
Color bool `json:"color,omitempty"`
Actor []string
}
func main(){
var movies = []Movie{
{
Title: "Casablanca",
Year: 1942 ,
Color: false,
Actor: []string{"Humphrey Bogart", "Ingrid Bergman"}
},
}
//data, err := json.Marshal(movies)
data, err := json.MarshalIndent(movies, "", " ")
if err != nil{
fmt.Println(err)
} else {
fmt.Printf("%s\n", data)
}
}
|
其中:
json.MarshalIndent(movies, "", " ")
将struct转换为带有合适缩进的字符串
- struct成员必须要大写开头,如果Actor改为actor,那么转换为字符串时将不包含actor这个key
结构体成员Tag
(一个结构体成员Tag是和在编译阶段关联到该成员的元信息字符串)转换为字符串后,Year将用release来显示
omitempty
选项,表示当Go语言结构体成员为空
或零值
时不生成该JSON对象(这里false为零值
)
解码(从json转换为struct)#
1
2
3
4
5
|
var titles []struct{ Title string }
if err := json.Unmarshal(data, &titles); err != nil {
log.Fatalf("JSON unmarshaling failed: %s", err)
}
fmt.Println(titles) // "[{Casablanca} {Cool Hand Luke} {Bullitt}]"
|
- 使用
json.Unmarshal()
- 上述这个例子只包含title,不包含其他属性。
文本和HTML模板#