go语言学习-struct、slice、映射

1,026 阅读3分钟

指针

Go 拥有指针。指针保存了值的内存地址。

类型 *T 是指向 T 类型值的指针。其零值为 nil。

var p *int

& 操作符会生成一个指向其操作数的指针。

i := 42
p = &i
  • 操作符表示指针指向的底层值。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21         // 通过指针 p 设置 i

这也就是通常所说的“间接引用”或“重定向”。

与 C 不同,Go 没有指针运算。

结构体

  • 结构体声明
type Vertex struct {
	X int
	Y int
}
  • 结构体初始化
v := Vertex{1, 2}
  • 结构体数据引用(结构体字段使用点号来访问)
v.x
  • 结构体指针
    • 如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以
p := &v
p.x
  • 结构体文法通过直接列出字段的值来新分配一个结构体
var (
	v1 = Vertex{1, 2}  // 创建一个 Vertex 类型的结构体
	v2 = Vertex{X: 1}  // Y:0 被隐式地赋予
	v3 = Vertex{}      // X:0 Y:0
	p  = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)

数组

  • 声明
//类型 [n]T 表示拥有 n 个 T 类型的值的数组
var a [10]int //数组a表示长度为10,内容为int类型,注意数组长度不可变
  • 赋值
//先声明,后赋值
var a [2] int
a[0] = 1
a[1] = 2
// 直接声明赋值
b := [2]int{1, 2}
  • 切片
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
	
// 更改切片的元素会修改其底层数组中对应的元素。
  • 切片文法
r := []int{1, 2}
  • 切片长度获取
len(r)
  • 切片容量获取
cap(r)
  • 切片的零值是nil
  • make来创建切片
a := make([]int, 5)  // len(a)=5
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
  • 切片可包含任何类型,甚至包括其它的切片。
  • 向切片追加元素(append)
a := make([]int, 5)
a = append(a, 0) // 添加0进入切片
a = append(a, 0, 1, 2, 3) // 添加0,1,2,3进入切片
  • range
for 循环的 range 形式可遍历切片或映射。

当使用 for 循环遍历切片时,每次迭代都会返回两个值。
第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。

映射

  • 映射的零值为nilnil映射既没有键,也不能添加键
  • 映射的文法
type Example struct {
    name string
}

var m map[string]Example
m = make(map[string]Example) //make 函数会返回给定类型的映射,并将其初始化备用

m["0"] = Example{
    "jack", // `,`必不可少
}

fmt.Println(m) // map[0:{jack}]
  • 修改映射
在映射 m 中插入或修改元素:

m[key] = elem
获取元素:

elem = m[key]
删除元素:

delete(m, key)
通过双赋值检测某个键是否存在:

elem, ok = m[key]
若 key 在 m 中,ok 为 true ;否则,ok 为 false。

若 key 不在映射中,那么 elem 是该映射元素类型的零值。

同样的,当从映射中读取某个不存在的键时,结果是映射的元素类型的零值。

注 :若 elem 或 ok 还未声明,你可以使用短变量声明:

elem, ok := m[key]
  • 函数也是值。它们可以像其它值一样传递
var show = func (name string) {
    fmt.Println(name)
}

var container (fn func(name string)) {
    fn("container")
}

container(show)
  • 闭包
func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

这个例子可以得知,sum会被后面的闭包沿用,并不是每次调用pos重新赋值为0