More Type: struct, slice and mapping
learn how to define new types based on existing types: This lesson covers the structures, arrays, slices, and maps.
Go write authors group, Go-zh group translation.
https://tour.go-zh.org/moretypes/1
- pointer
Go has pointers. Save the memory address pointer value.
Type *T
is a pointer T
type value of the pointer. Its value is zero nil
.
var p *int
&
Operator generates a pointer to its operands.
i := 42
p = &i
*
Operator indicates the bottom pointer value.
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
This is commonly referred to as "indirect references" or "redirect."
And C different, Go no pointer arithmetic.
// +build OMIT
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // 指向 i
fmt.Println(*p) // 通过指针读取 i 的值
*p = 21 // 通过指针设置 i 的值
fmt.Println(i) // 查看 i 的值
p = &j // 指向 j
*p = *p / 37 // 通过指针对 j 进行除法运算
fmt.Println(j) // 查看 j 的值
}
- Structure
A structure ( struct
) is a set of fields (field).
// +build OMIT
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
- Structure fields
Field uses dot structures to access.
// +build OMIT
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
- Structure pointer
Structure fields can be accessed by a pointer to a structure.
If we have a pointer to a structure p
, you can (*p).X
access its fields X
. But so write too long-winded, so the language also allows us to use implicit indirect reference, write directly p.X
on it.
// +build OMIT
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)
}
- Structure grammar
Structure grammar to assign a new value field structure by a direct listed.
Use Name:
syntax to list only part of the field. (Irrespective of the order of field names.)
Special prefix &
returns a pointer to structure.
// +build OMIT
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // 创建一个 Vertex 类型的结构体
v2 = Vertex{X: 1} // Y:0 被隐式地赋予
v3 = Vertex{} // X:0 Y:0
p = &Vertex{1, 2} // 创建一个 *Vertex 类型的结构体(指针)
)
func main() {
fmt.Println(v1, p, v2, v3)
}
- Array
The type of [n]T
representation has n
a T
array of values of type.
expression
var a [10]int
It will be variable a
declared as an array with 10 integers.
Part of its length of the array type and therefore the size of the array can not be changed. This appears to be a limit, but that's OK, Go provides a more convenient way to use an array.
// +build OMIT
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
- slice
The size of each array are fixed. The slice was the size of the array elements to provide dynamic, flexible viewing angle. In practice, the slice is more commonly used than arrays.
Type []T
represents an element type T
of slice.
Slice defined by two subscripts, i.e. a lower bound and an upper bound, both separated by colons:
a[low : high]
It will choose a half-open range, including the first element, but excluding the last element.
The following expression creates a slice that contains a
the index of the elements from 1-3:
a[1:4]
// +build OMIT
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s)
}
- Slice like a reference to the array
Slice does not store any data, it merely describes some of the underlying array.
Change slices modify the underlying array element corresponding elements.
Share it with the underlying array sections are observed to such modifications.
// +build OMIT
package main
import "fmt"
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names)
a := names[0:2]
b := names[1:3]
fmt.Println(a, b)
b[0] = "XXX"
fmt.Println(a, b)
fmt.Println(names)
}
- Slice grammar
Grammar Grammar no array sections similar length.
This is an array of grammar:
[3]bool{true, true, false}
Below this will create one and the same array above, and then constructed a reference to its slice:
[]bool{true, true, false}
// +build OMIT
package main
import "fmt"
func main() {
q := []int{2, 3, 5, 7, 11, 13}
fmt.Println(q)
r := []bool{true, false, true, true, false, true}
fmt.Println(r)
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
fmt.Println(s)
}
- The default behavior slices
During slicing, you can use it to override the default behavior of bounds.
The default value of the slice lower bound 0
, the upper bound is the length of the slice.
For array
var a [10]int
, The following sections are equivalent:
a[0:10]
a[:10]
a[0:]
a[:]
// +build OMIT
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
s = s[1:4]
fmt.Println(s)
s = s[:2]
fmt.Println(s)
s = s[1:]
fmt.Println(s)
}
- Slice length and capacity
Slice has length and capacity .
The length of the slice is the number of elements it contains.
The capacity is the number of slices in the first element from its beginning to the end of the number of the underlying array element.
Slice s
length and capacity by expressions len(s)
and cap(s)
acquired.
As long as sufficient capacity, you can extend a slice by slice again. Try to modify a slicing the sample program, making it longer than the capacity (which is about to expand beyond its capacity range), and see what happens.
// +build OMIT
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// 截取切片使其长度为 0
s = s[:0]
printSlice(s)
// 拓展其长度
s = s[:4]
printSlice(s)
// 舍弃前两个值
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
- nil slice
Zero value slice is nil
.
nil slice length and a capacity of 0 and no underlying array.
// +build OMIT
package main
import "fmt"
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
}
- Create a slice with make
Slice with a built-in function can make
be created, and this is the way you create a dynamic array.
make
Function allocates an array element value of zero and returns a reference to its slice:
a := make([]int, 5) // len(a)=5
To specify its capacity, the need to make
pass the third parameter:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
// +build OMIT
package main
import "fmt"
func main() {
a := make([]int, 5)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
c := b[:2]
printSlice("c", c)
d := c[2:5]
printSlice("d", d)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
- Slice slice
Slice may comprise any type, even other slices.
// +build OMIT
package main
import (
"fmt"
"strings"
)
func main() {
// 创建一个井字板(经典游戏)
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// 两个玩家轮流打上 X 和 O
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], " "))
}
}
- To slice an additional element
Slices add a new element is commonly used in the operation, aims to provide a built-Go append
function. Built-in functions [[ https://go-zh.org/pkg/builtin/#append ] [documentation]] have this function in detail.
func append(s []T, vs ...T) []T
append
The first parameter s
is a type of element T
sections, other types of T
values will be appended to the end of the slice.
append
The result is a slice that contains all the elements of the original plus the newly added sections element.
When s
the time of the underlying array is too small to accommodate all the values given, it will be assigned a larger array. Returned slice will point to this newly allocated array.
(To learn more about slices, please read the article [[ https://blog.go-zh.org/go-slices-usage-and-internals ] [Go sections: Usage and nature]].)
// +build OMIT
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// 添加一个空切片
s = append(s, 0)
printSlice(s)
// 这个切片会按需增长
s = append(s, 1)
printSlice(s)
// 可以一次性添加多个元素
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
- Range
for
Loop range
form or map may traverse sections.
When using for
the time slicing cycle through each iteration will return two values. A copy of the first element is the current element index, the second index corresponding to the value.
// +build OMIT
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
- range (cont.)
Index or value may be given _
to ignore it.
for i, _ := range pow
for _, value := range pow
If you only need the index, ignore the second variable.
for i := range pow
// +build OMIT
package main
import "fmt"
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
- Exercise: Slice
Achieved Pic
. It should return the length of a dy
slice, wherein a length of each element dx
, the element type uint8
of a slice. When you run this program, it will be interpreted as grayscale each integer value (well, in fact, is the blue value) and displays the image to which it corresponds.
Select the image you to decide. Several interesting functions include (x+y)/2
, x*y
, x^y
, x*log(y)
and x%(y+1)
.
(Hint: use a loop to assign [][]uint8
each []uint8
; please use uint8(intValue)
between type conversion; you might use math
function package.)
// +build no-build OMIT
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
}
func main() {
pic.Show(Pic)
}
- Mapping (
map
)
Mapping maps keys to values.
Mapping zero value nil
. nil
Mapping neither bond nor add key.
make
Function returns the given type of mapping, and initializes its standby.
// +build OMIT
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
- Mapping of grammar
Mapping grammar and structure similar, but must have a key name.
// +build OMIT
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
func main() {
fmt.Println(m)
}
- Mapping of grammar (cont.)
If the top-level type is just a type name, you can omit it from the elements of grammar.
// +build OMIT
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
func main() {
fmt.Println(m)
}
- Modifying the mapping
Mapping m
inserted or modified elements:
m[key] = elem
Gets the element:
elem = m[key]
Removing elements:
delete(m, key)
Whether there is a key assignment by double detection:
elem, ok = m[key]
If key
in the m
middle, ok
it is true
; otherwise, ok
is false
.
If key
not in the map, then elem
a zero value element is the mapping type.
Similarly, when reading from a key mapping does not exist, the result is a zero value element type mapping.
Note : If you elem
or ok
has not been declared, you can use short variable declarations:
elem, ok := m[key]
// +build OMIT
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}
- Exercise: Mapping
Achieved WordCount
. It should return a map which contains the string s
number in each "word" of. Function wc.Test
will perform a series of test cases for this function, and outputs success or failure.
You will find [[ https://go-zh.org/pkg/strings/#Fields ] [strings.Fields]] helpful.
// +build OMIT
package main
import (
"golang.org/x/tour/wc"
)
func WordCount(s string) map[string]int {
return map[string]int{"x": 1}
}
func main() {
wc.Test(WordCount)
}
- Function value
Functions are also values. Other values can be passed as they are the same.
Function values may be used as parameters or function return values.
// +build OMIT
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
- Closure function
Go function may be a closure. A closure is a function value, it refers to a function of the variables outside the body. This function can access and impart its reference value variable, in other words, the function of these variables are "bound" together.
For example, the function adder
returns a closure. Each closure are bound at their respective sum
upper variable.
// +build OMIT
package main
import "fmt"
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),
)
}
}
- Exercise: Fibonacci closure
Let's use the function to do fun things.
Implement a fibonacci
function that returns a function (closure), which returns a closure [[ https://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3 91 is E5% A5%%%% 95% B0 E6 E5% 88% 97% ] (0, 1, 1, 2, 3, 5, ...)
[fibonacci]] .
// +build no-build OMIT
package main
import "fmt"
// 返回一个“返回int的函数”
func fibonacci() func() int {
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
- Congratulations!
You have completed this course!
You can return to [[/ list] [list of modules]] to see what the next learning, or continue [[ JavaScript: the Click ( '.next-Page')] [behind the course]].