Tour of Go 01(中英互译)

67 阅读6分钟

More types structs, slices, and maps

structs 结构体

Pointers to structs

Struct fields can be accessed through a struct pointer. 可以通过结构指针访问结构字段。

To access the field X of a struct when we have the struct pointer p we could write (*p).X. However, that notation is cumbersome, so the language permits us instead to write just p.X, without the explicit dereference. 当我们拥有结构指针 p 时,要访问结构的字段 X ,我们可以编写 (*p).X 。然而,这种表示法很麻烦,所以该语言允许我们只写 p.X ,而无需显式取消引用。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	p := &v
	p.X = 1e9
	fmt.Println(v)
}

Struct Embedding结构体嵌入

type base struct {
    num int
}
type container struct {
    base
    str string
}

上面这段就是结构体嵌入,在使用字面量来声明结构时候,需要显式传入初始化的值

co := container{
        base: base{
            num: 1,
        },
        str: "some name",
    }

如果同时base结构体实现了接口,那么container也可以使用这个接口

type describer interface {
        describe() string
    }
	
func (b base) describe() string {
    return fmt.Sprintf("base with num=%v", b.num)
}

slices

An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array. In practice, slices are much more common than arrays. 数组具有固定大小。另一方面,切片是对数组元素的动态大小、灵活的视图。实际上,切片比数组更常见。

The type []T is a slice with elements of type T.

[]T 类型是一个包含 T 类型元素的切片。

A slice is formed by specifying two indices, a low and high bound, separated by a colon: 通过指定两个索引(下限和上限)来形成切片,用冒号分隔:

Slices are like references to arrays切片类似于数组的引用

A slice does not store any data, it just describes a section of an underlying array. 切片不存储任何数据,它只是描述底层数组的一部分。

Changing the elements of a slice modifies the corresponding elements of its underlying array. 更改切片的元素会修改其底层数组的相应元素。

func main() {
	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}
	fmt.Println(names)

	a := names[0:2]
	b := names[1:3]
	fmt.Println(a, b)//[John Paul] [Paul George]

	b[0] = "XXX"
	a[1] = "new a"
	fmt.Println(a, b)//[John new a] [new a George]
	fmt.Println(names)//[John new a George Ringo]
}

Slice literals 切片字面量

type Vertex struct {
	i int
	b bool
}
func main() {
	q := []int{2, 3, 5, 7, 11, 13}
	fmt.Println(q)

	r := []bool{true, false, true, true, false, true}
	fmt.Println(r)
	var nr = &r
	(*nr)[1] = true
	fmt.Println(r)//[true true true true false true]

	s := []Vertex{
		{2, true},
		{3, false},
		{5, true},
		{7, true},
		{11, false},
		{13, true},
	}
	fmt.Println(s)//[{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
}

Slice defaults

The default is zero for the low bound and the length of the slice for the high bound. 下限的默认值为零,上限的切片长度为默认值。

Slice length and capacity 切片长度和容量

A slice has both a length and a capacity. 切片具有长度和容量。

The length of a slice is the number of elements it contains. 切片的长度是它包含的元素的数量。

The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice. 切片的容量是底层数组中元素的数量,从切片中的第一个元素开始计算。

The length and capacity of a slice s can be obtained using the expressions

Nil slices

The zero value of a slice is nil. 切片的零值为 nil 。

A nil slice has a length and capacity of 0 and has no underlying array. nil 切片的长度和容量为 0,并且没有底层数组。

func main() {
	var s []int
	fmt.Println(s, len(s), cap(s))//[] 0 0
	if s == nil {
		fmt.Println("nil!")
	}
}

Creating a slice with make

The make function allocates a zeroed array and returns a slice that refers to that array: make函数分配一个零值数组并且返回一个引用该数组的slice

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

slice of slices

Slices can contain any type, including other slices. 切片可以包含任何类型,包括其他切片。

func main() {
	// Create a tic-tac-toe board.
	board := [][]string{
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
		[]string{"_", "_", "_"},
	}

	// The players take turns.
	board[0][0] = "X"
	board[2][2] = "O"
	board[1][2] = "X"
	board[1][0] = "O"
	board[0][2] = "X"

	for i := 0; i < len(board); i++ {
		fmt.Printf("%s\n", strings.Join(board[i], " "))
	}
}

Appending to a slice 附加到切片

将新元素附加到切片是很常见的,因此 Go 提供了一个内置的 append 函数。内置包的文档描述了 append 。

func append(s []T, vs ...T) []T The first parameter s of append is a slice of type T, and the rest are T values to append to the slice. append 的第一个参数 s 是一个 T 类型的切片,其余参数是要附加到切片的 T 值。 The resulting value of append is a slice containing all the elements of the original slice plus the provided values. append 的结果值是一个切片,其中包含原始切片的所有元素加上提供的值。

If the backing array of s is too small to fit all the given values a bigger array will be allocated. The returned slice will point to the newly allocated array. 如果 s 的后备数组太小而无法容纳所有给定值,则会分配一个更大的数组。返回的切片将指向新分配的数组。

func main(){
    var s init[]
    s = append(s,0)
    // We can add more than one element at a time.
	s = append(s, 2, 3, 4)
}

Range 排列

The range form of the for loop iterates over a slice or map. for 循环的 range 形式迭代切片或映射。

When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index. 在切片上进行测距时,每次迭代都会返回两个值。第一个是索引,第二个是该索引处元素的副本。

var pow = init[]{1, 2, 4, 8, 16, 32, 64, 128}
for i,v := range pow {
    fmt.Printf("2**%d = %d\n", i, v)
}

输出结果:


2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128

Maps

A map maps keys to values. 映射将键映射到值。

The zero value of a map is nil. A nil map has no keys, nor can keys be added. map的零值是 nil .nil 映射没有键,也不能添加键。

The make function returns a map of the given type, initialized and ready for use. make 函数返回给定类型的映射,已初始化并准备好使用。

package main

import "fmt"
//定义结构体
type Vertex struct {
	Lat, Long float64
}
//声明m的类型为map,键值为string类型,值为Vertex类型
var m map[string]Vertex

func main() {
	fmt.Println(m)
	//通过make初始化m
	m = make(map[string]Vertex)
	m["Bell Labs"] = Vertex{
		40.68433, -74.39967,
	}
	fmt.Println(m["Bell Labs"],m)
}

Map literals map字面量

If the top-level type is just a type name, you can omit it from the elements of the literal. 如果顶级类型只是一个类型名称,您可以从文字的元素中省略它。

type Vertex struct {
	Lat, Long float64
}

var m = map[string]Vertex{
	"Bell Labs": Vertex{40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}

func main() {
	fmt.Println(m)
}

Mutating Maps 改变map

Insert or update an element in map m: 在地图 m 中插入或更新元素:

m[key] = elem Retrieve an element: 检索元素:

elem = m[key] Delete an element: 删除一个元素:

delete(m, key) Test that a key is present with a two-value assignment: 测试一个键是否存在一个二值赋值:

elem, ok = m[key] If key is in m, ok is true. If not, ok is false. 如果 key 在 m 中,则 ok 是 true 。如果不是, ok 就是 false 。

If key is not in the map, then elem is the zero value for the map's element type. 如果 key 不在地图中,则 elem 是地图元素类型的零值。

Note: If elem or ok have not yet been declared you could use a short declaration form: 注意:如果尚未声明 elem 或 ok ,您可以使用简短的声明形式:

elem, ok := m[key]

m := make(map[string]int)
m["answer"] = 42
s,err := m["answer"]

# Tour of Go 02 :methods and interface