Go是有指针的,*T
定义一个指向T类型的指针,其缺省值为nil
.
类似地,&
操作符可以取操作数的地址。
而*
操作符也可以取指针指向的值
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的数组。
数组的长度也是它类型的一部分,所以其长度不能改变,这看起来不方便,但不用担心,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], " ")) } }
|
运行:
切割slice
slice可被切割s[lo:hi]
代表包含下标lo
至 hi-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,它返回dy
的slice
,每个元素是dy
的8位无符号整形。当运行这个程序时,它将显示你的图片,将整形数以灰度呈现。
图片任由你选择,有一些有趣的函数如(x+y)/2
,x*y
,x^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