Contents
  1. 1. struct
    1. 1.1. struct指针
    2. 1.2. struct lteral
  2. 2. 数组
  3. 3. slice
    1. 3.1. slice of slice
    2. 3.2. 切割slice
    3. 3.3. make slice
    4. 3.4. nil slice
    5. 3.5. 向slice添加元素
    6. 3.6. for range
  4. 4. slice练习

Go是有指针的,*T定义一个指向T类型的指针,其缺省值为nil.

1
var p *int

类似地,&操作符可以取操作数的地址。

1
2
i := 42
p = &i

*操作符也可以取指针指向的值

1
2
fmt.Println(*p) // 通过指针p读取i值
*p = 21 // 通过指针p更新i值

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

struct

struct是一组的集合

1
2
3
4
5
6
7
8
9
10
11
12
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}

struct的域可以通过.来存取。

1
2
3
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)

struct指针

其定义与基本数据类型无异,但需要注意的是通过它引用域也是使用.操作符,而无显式的解引用过程。

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

struct lteral

struct literal通过列出struct域的值来表示一个新建的struct.你也可以通过name:值的方式来只指定一个子集。
还可以同时使用&操作符来直接返回指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3)
}

数组

[n]T表示长度为n类型为T的数组。

1
var a [10]int

数组的长度也是它类型的一部分,所以其长度不能改变,这看起来不方便,但不用担心,Go提供一系列操作数组的便捷方法。
(也就是下面提到的slice了。)

slice

slice指向一组数值,且包含长度。[]T是一个类型为T的slice.而len(primes)则返回名为primes的slice的长度。

1
2
3
4
5
6
7
8
9
10
11
12
package main
import "fmt"
func main() {
primes := []int{2, 3, 5, 7, 11, 13}
fmt.Println("primes ==", primes)
for i := 0; i < len(primes); i++ {
fmt.Printf("primes[%d] == %d\n", i, primes[i])
}
}

slice of slice

slice可包含slice等任意类型。

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
package main
import (
"fmt"
"strings"
)
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[2][0] = "X"
board[1][0] = "O"
board[0][2] = "X"
for i := 0; i < len(board); i++ {
fmt.Printf("%s\n", strings.Join(board[i], " "))
}
}

运行:

1
2
3
X _ X
O _ _
X _ O

切割slice

slice可被切割s[lo:hi]代表包含下标lohi-1在内的元素,也就是s[lo:lo]为空,s[lo:lo+1]包含一个元素。
同样可以省略起始或截止位,代表从头或至尾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("s ==", s)
fmt.Println("s[1:4] ==", s[1:4])
// missing low index implies 0
fmt.Println("s[:3] ==", s[:3])
// missing high index implies len(s)
fmt.Println("s[4:] ==", s[4:])
}

运行:

1
2
3
4
s == [2 3 5 7 11 13]
s[1:4] == [3 5 7]
s[:3] == [2 3 5]
s[4:] == [11 13]

make slice

可使用make函数来生成slice,它生成一个全0的数组并返回一个引用该数组的slice.

1
a := make([]int, 5) // len(a)=5

要指定容量,指定第三个参数即可。

1
2
3
4
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

可见可用cap()方法来得到slice容量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
}

运行

1
2
3
4
5
6
a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
c len=2 cap=5 [0 0]
d len=3 cap=3 [0 0 0]
Program exited.

nil slice

slice的0值(缺省值)为nil,其长度和容量都是0.

1
2
3
4
5
6
7
8
9
10
11
package main
import "fmt"
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
}

向slice添加元素

Go为slice提供内置的append方法,其原型为

1
func append(s []T, vs ...T) []T

其第一参数为类型为T的slice,后为需要追加的类型为T的值。其返回值为原元素+append的元素的slice,如果原slice容量不够,会返回一个新建的slice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than one element at a time.
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)
}

运行:

1
2
3
4
5
6
len=0 cap=0 []
len=1 cap=2 [0]
len=2 cap=2 [0 1]
len=5 cap=8 [0 1 2 3 4]
Program exited.

for range

for循环结合range关键字可以遍历一个slice.

1
2
3
4
5
6
7
8
9
10
11
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的每次迭代返回两个值,分别是下标和对应值的copy,也可以使用_来略过下标,或者可以只指定下标。

1
2
for i := range pow {}
for _, value := range pow {}

slice练习

实现Pic,它返回dyslice,每个元素是dy的8位无符号整形。当运行这个程序时,它将显示你的图片,将整形数以灰度呈现。
图片任由你选择,有一些有趣的函数如(x+y)/2,x*yx^y.
(你需要使用循环来为[][]unit8分配每个[]uint8)
(使用unit8(intValue)来转换数值类型)

注:这个程序只能在golang.org上完成,因为它import了教程自带的包。
网址为https://tour.golang.org/moretypes/15
题为:

1
2
3
4
5
6
7
8
9
10
11
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
}
func main() {
pic.Show(Pic)
}

我的答案:灰度为x,y坐标积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
r := make([][]uint8,dy)
for i := range r {
e := make([]uint8,dy)
for j := range e{
e[j] = uint8(i*j)
}
r[i] = e
}
return r
}
func main() {
pic.Show(Pic)
}

打印出的图案也很有趣:

同样的,建议大家自行试验,PS: x^y的图案也很有趣。
再次附上网址:https://tour.golang.org/moretypes/15

Contents
  1. 1. struct
    1. 1.1. struct指针
    2. 1.2. struct lteral
  2. 2. 数组
  3. 3. slice
    1. 3.1. slice of slice
    2. 3.2. 切割slice
    3. 3.3. make slice
    4. 3.4. nil slice
    5. 3.5. 向slice添加元素
    6. 3.6. for range
  4. 4. slice练习