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<dy; i++ {
one_a := make([]uint8, dx)
a = append(a, one_a)
}
for i:=0; i<dy; i++ {
for j:=0; j<dx; j++ {
a[i][j] = uint8(i%(j+1))
}
}
return a
}
func main() {
pic.Show(Pic)
}
映射
- 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