Go语言学习Part3:struct、slice和映射

https://tour.go-zh.org/moretypes/2
https://tour.go-zh.org/list 还差两部分就学完啦哈哈,毕竟都用这个写了fab

感想:想当年C++学习的时候,都没有这么认真过,过去的时光里可真的是傻乎乎的囫囵吞枣!

指针

  • &变量:指向其操作数的指针
  • *指针:表示指针指向的底层值
  • Go木有指针运算
//case 1
package main

import "fmt"

func main() {
	i, j := 20, 100

	p := &i         // 指向 i
	fmt.Println(*p) // 通过指针读取 i 的值
	*p = 21         // 通过指针设置 i 的值
	fmt.Println(i)  // 查看 i 的值

	p = &j         // 指向 j
	*p = *p / 10   // 通过指针对 j 进行除法运算
	fmt.Println(j) // 查看 j 的值
}

结构体

  • C里面也是有结构体
  • Go的结构体是一组字段field
  • 具体访问使用.
  • 结构体的值也可以用结构体指针来访问
  • 结构体如果没有初始值,会给一个默认的
//case 2
package main

import "fmt"

type Pos struct {
	X int
	Y int
	Z bool
}

func main() {
	t := Pos{X:1, Y:2}
	p := &t
	fmt.Println(t.X)
	fmt.Println(p.X)
	fmt.Println((*p).X)
	fmt.Println((*p))
}

静态数组

  • 变量声明为10个整数的数组
//case 3
package main

import "fmt"

var primes = [6]int{2, 3, 5, 7, 11, 13}

func main() {
    fmt.Println(primes)
}
  • 结合了python的性能,数组流弊,可以用切片(前闭后开)
    • 切片并不存储任何数据,它只是描述了底层数组中的一段。
    • 更改切片的元素会修改其底层数组中对应的元素。
    • 与它共享底层数组的切片都会观测到这些修改。
    • 切片下界的默认值为 0,上界则是该切片的长度。
//case 4
package main

import "fmt"

var primes = [6]int{2, 3, 5, 7, 11, 13}

func main() {
    a := primes[0:2]
    b := primes[0:5]
    primes[1] = 100
    c := primes
    c[1] = 200
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
    fmt.Println(primes)
}

切片

  • 切片拥有 长度 和 容量。
    • 切片的长度就是它所包含的元素个数。
    • 切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
    • 切片 s 的长度和容量可通过表达式 len(s) 和 cap(s) 来获取。
    • 长度就是切片大小;
    • 容量比较神奇,前切容量变小,后切容量不变hh,见case5
  • 切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。
  • 切片追加新元素append
  • 切片的用法和本质:https://blog.go-zh.org/go-slices-usage-and-internals
  • 切片扩容:https://www.jb51.net/article/143729.htm
    • append一个元素的扩容,见case8
    • append一堆元素的扩容,见case9【2倍不够就是偶数len或者奇数len+1】
//case 5
package main

import "fmt"

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

func main() {
	s := []int{2, 3, 5, 7, 11, 13}
	printSlice(s)

	// 截取切片使其长度为 0
	s = s[:0]
	printSlice(s)
	// x x x x x x cap=6
	//len=0

	// 拓展其长度
	s = s[:5]
	printSlice(s)
	//x x x x x x cap=6
	//2 3 5 7 11 len=5

	// 舍弃前三个值
	s = s[3:]
	printSlice(s)
	//x x x cap=3
	//7 11 len=2
	
	// 舍弃前1个值
	s = s[1:]
	printSlice(s)
	// x x cap=2
	// 11 len=1
}
//case 9
package main

import "fmt"

func main() {
	var s []int
	printSlice(s)

	s = append(s, 0)
	printSlice(s)
	//cap=1

	s = append(s, 1)
	printSlice(s)
	//cap=2

	s = append(s, 2,3,4)
	printSlice(s)
	//cap=6 2倍也不够,那就len+1,或者len
		
	s = append(s, 5)
	printSlice(s)
	//cap=6
	
	s = append(s, 6)
	printSlice(s)
	//cap=12
	
	s = append(s, 7)
	printSlice(s)
	////cap=12
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

  • 切片的零值是 nil。
    • nil 切片的长度和容量为 0 且没有底层数组。
//case 6
package main

import "fmt"

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

import "fmt"

func main() {
	var s []int
	printSlice(s)

	s = append(s, 0)
	printSlice(s)
    //cap=1
    
	s = append(s, 1)
	printSlice(s)
	//cap=2

	s = append(s, 2)
	printSlice(s)
	//cap=4
	
	s = append(s, 3)
	printSlice(s)
	//cap=4
	
	s = append(s, 4)
	printSlice(s)
	//cap=8
	
	s = append(s, 5)
	printSlice(s)
	//cap=8
	
	s = append(s, 6)
	printSlice(s)
	//cap=8
	
	s = append(s, 7)
	printSlice(s)
	//cap=8
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

Range

  • 遍历切片,每次迭代返回两个值,一个是下标,一个是元素值
  • 可以用_忽略 case10
//case 10
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)
	}
}

动态数组

//case 7
package main

import "fmt"

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

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

	c := b[:2]
	printSlice("c", c)
	printSlice("b", b)
	//b cap=5 len=0
	//c cap=5 len=2

	d := c[2:5]
	printSlice("d", d)
	//d cap=3 len=3
}

func printSlice(s string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		s, len(x), cap(x), x)
}

练习题-切片

//case 11
package main

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

func Pic(dx, dy int) [][]uint8 {
	var a [][]uint8
	for i:=0; i

映射

  • make 用来为 slice,map 或 chan 类型分配内存和初始化一个对象(注意:只能用在这三种类型上),跟 new 类似
  • 映射的零值为 nil 。nil 映射既没有键,也不能添加键。
  • 必须要键名
  • 删除元素:delete(m, key)
  • elem, ok := m[key] //短变量声明,查看某个key有木有
//case 12
package main
import "fmt"
type Info struct {
    age int
    school string
}
var t map[string]Info
func main() {
    t = make(map[string]Info)
    t["Lucy"] = Info {
        10 ,
		"language school",
    }
    fmt.Println(t["Lucy"])
}

练习题-映射

//case 13
package main

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

func WordCount(s string) map[string]int {
	words := strings.Fields(s)
	//
	var res map[string]int
	res = make(map[string]int)
	for i:=0; i < len(words); i++ {
		var temp string= words[i]
		_, ok := res[temp]
		if ok {
			res[temp]++
		} else {
			res[temp]=1
		}
	}
	return res
}

func WordCount2(s string) map[string]int {
	words := strings.Split(s, " ")
	var res map[string]int
	res = make(map[string]int)
	for i:=0; i < len(words); i++ {
		var temp string= words[i]
		_, ok := res[temp]
		if ok {
			res[temp]++
		} else {
			res[temp]=1
		}
	}
	return res
}
func main() {
	//wc.Test(WordCount)
	res := WordCount("my   name  is  Lucy")
	fmt.Println(res)
	res = WordCount2("my   name  is  Lucy")
	fmt.Println(res)
}


函数也可作为参数

//case 14
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))    // 25= 16+9
	fmt.Println(compute(math.Pow)) // 3*3*3*3
}

函数的闭包

  • Go 函数可以是一个闭包。闭包是一个函数值,它引用了其函数体之外的变量。该函数可以访问并赋予其引用的变量的值
//case 15
//pos和neg使用了两个sum副本,但是多次调用pos修改的是同一个sum
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),
		)
	}
}

练习题-斐波纳契闭包

//case 16
package main

import "fmt"

// 返回一个“返回int的函数”
func fibonacci() func(int) int {
	a:=0
	b:=1
	return func(x int) int {
		if x==0 {
			return a
		}
		if x==1 {
			return b
		}
		c := a+b;
		a = b
		b = c
		return b;
	}
}

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

函数学习之旅

  • strings.Join(数组, " ")
  • strings.Split() //多个连续的空格就跪了
  • strings.Field(): https://go-zh.org/pkg/strings/#Fields

你可能感兴趣的:(Go)