Go语言复杂类型: struct、slice 和 map篇三

/ Go技术 / 没有评论 / 3567浏览

gopher

##复杂类型: struct、slice 和 map 学习如何基于已有类型定义新的类型:本课涵盖了结构体、数组、slice 和 map。

指针

    var p *int
    i := 42
    p = &i
fmt.Println(*p) //通过指针 p 读取 i
*p = 32 //通过指针 p 设置 i
package main

import "fmt"

func main() {
	i , j := 56, 128
	p := &i				// point to i
	fmt.Println(*p)		// read i through the pointer
	*p =21				// set i through the pointer
	fmt.Println(i)		// see the new value of i

	p = &j				// point to j
	*p = *p/24			// divide j through the pointer
	fmt.Println(j)		// see the new value of j
}

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

结构体

package main

import "fmt"

type Coordinate struct {
	x int
	y int
}

func main() {
	fmt.Println(Coordinate{1,2})
}

结构体字段

package main

import "fmt"

type CoordinateFiled struct {
	X int
	Y int
}

func main() {
	v := CoordinateFiled{1,6}
	v.X =4
	fmt.Println(v.X)
}

结构体指针

package main

import (
	"fmt"
	"../hello"
	)

func main() {
	v := hello.Coordinate{2, 6}
	p := &v
	p.X = 1e9

	fmt.Println(v)
}

通过指针间接的访问是透明的。

结构体文法

package main

import (
	"fmt"
	"../hello"
	)

var (
	v1 = hello.Vertex{1,2}
	v2 = hello.Vertex{X:1}
	v3 = hello.Vertex{}
	p = &hello.Vertex{1,2}
)

func main() {
	fmt.Println(v1,p,v2,v3)
}

数组

var a [10]int

定义变量 a 是一个有十个整数的数组。

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)
}

slice

package main

import "fmt"

func main() {
	s := [] int{2,3,5,7,9,11}
	fmt.Println("s ==",s)

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

slice 的 slice

package main

import (
	"fmt"
	"strings"
)

func main() {
	game := [][]string{
		[]string {"-","-","-"},
		[]string {"-","-","-"},
		[]string {"-","-","-"},
	}
	// The players take turns.
	game[0][0] = "X"
	game[2][2] = "O"
	game[2][0] = "X"
	game[1][0] = "O"
	game[0][2] = "X"

	printBoard(game)
}

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

对 slice 切片

s[lo:hi]

表示从 lo 到 hi-1 的 slice 元素,含前端,不包含后端。因此

s[lo:lo]

是空的

s[lo:lo+1]

有一个元素

package main

import "fmt"

func main()  {
	s := []int{3,5,7,9,11,13,15,17}
	fmt.Println("s ==",s)
	fmt.Println("s[1:4] ==",s[1:4])

	//省略下标代表从0开始
	fmt.Println("s[:4] ==",s[:4])

	//省略上标到len(s)结束
	fmt.Println("s[4:] ==",s[4:])
}

构造 slice

a := make([]int, 5)  // len(a)=5
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

完整代码例如:

package main

import "fmt"

func main() {
	a := make([]int,5)
	printSlice("a",a)

	b := make([]int,0,5)
	printSlice("b",b)

	c := b[:3]
	printSlice("c",c)

	d := b[3: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)
}

nil slice

例如:

package main

import "fmt"

func main() {
	var s []int

	fmt.Println(s,len(s),cap(s))

	if s == nil {
	fmt.Println("nil!")

	}
}

向 slice 添加元素

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

例如:

package main

import (
	"../hello"
	)

func main() {
	var a []int
	hello.PrintSlice("a",a)

	// append works on nil slices.
	a = append(a,0)
	hello.PrintSlice("a",a)

	// the slice grows as needed.
	a = append(a,1)
	hello.PrintSlice("a",a)

	// we can add more than one element at a time.
	a = append(a,2,3,4,5,6,7,8,)
	hello.PrintSlice("a",a)
}

range

例如:

package main

import "fmt"

var pow1 = []int{1,2,4,8,16,32,64,128}

func main()  {
	for i,v := range pow1{
		fmt.Printf("2**%d = %d\n", i, v)
	}
}

range(续)

例如:

package main

import "fmt"

func main() {
	pow := make([]int,10)
	for i := range pow{
		pow[i] = 1<<uint(i)
	}
	for _,value := range pow{
		fmt.Printf("%d\n", value)
	}
}

练习:slice

例如;

package main

import (
	"golang.org/x/tour/pic"
)

func Pic(dx, dy int) [][]uint8 {
	var array = [][]uint8{}
	for i := 0;i < dy;i++{
		array = append(array, make([]uint8,dx))
	}
	return array
}

func main() {
	pic.Show(Pic)
}

提示 1. (需要使用循环来分配 [][]uint8 中的每个 []uint8 。) 2. (使用 uint8(intValue) 来在类型之间进行转换。)

map

例如;

package main

import (
	"fmt"
	"hello-go/hello"
)
var m map[string] hello.VertexLL

func main() {
	m = make(map[string] hello.VertexLL)
	m["Bell Labs"] = hello.VertexLL{40.68433, -74.39967,}
	fmt.Println(m["Bell Labs"])
}

map 的文法

例如:

package main

import (
	"fmt"
	"hello-go/hello"
)

var m1 = map[string]hello.VertexLL{
	"Bell Labs":{40.68433, -74.39967},
	"Google":hello.VertexLL{37.42202, -122.08408,},
}

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

map 的文法(续)

例如:

package main

import (
	"fmt"
	"hello-go/hello"
)

var m2 = map[string]hello.VertexLL{
	"Bell Labs":{40.68433, -74.39967},
	"Google":{37.42202, -122.08408,},
}

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

修改 map

m[key] = elem
elem = m[key]
delete(m, key)
elem, ok = m[key]
1. 如果 `key` 在 `m` 中, ok 为 true。否则, ok 为 false,并且 elem 是 map 的元素类型的零值。
2. 同样的,当从 map 中读取某个不存在的键时,结果是 map 的元素类型的零值。

例如:

package main

import "fmt"

func main() {
	m := make(map[string]int)
	m["Answer"] = 34
	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)

}

练习:map

提示:你会发现 strings.Fields 很有帮助。

代码:

package main

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	strArray := strings.Fields(s)
	count := make(map[string]int)
	for i := 0;i < len(strArray); i++{
		str := strArray[i]
		_,ok := count[str]
		if !ok{
			count[str] = 1
		} else {
			count[str] += 1
		}
	}
	return count
}

func main() {
	wc.Test(WordCount)
}

函数值

例如:

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(6,8))
	fmt.Println(compute(hypot))
	fmt.Println(compute(math.Pow))
}

结果:

10
5
81

函数的闭包

例如:

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),
		)
	}
}

输出结果:

0 0
1 -2
3 -6
6 -12
10 -20
15 -30
21 -42
28 -56
36 -72
45 -90

简单分析: 1. adder()返回的是函数 2. 循环中多次调用pos,可见pos的sum相对pos是全局的

练习:斐波纳契闭包

F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)
1、1、2、3、5、8、13、21、34

代码如下:

package main

import "fmt"

// fibonacci 函数会返回一个返回 int 的函数。
func fibonacci() func() int {
	i ,j := 0,1
	return func() int {
		tmp := i
		i , j = j ,i + j
		return tmp
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}