GO 语言基础学习
Drunkbaby Lv6

golang 基础学习

GO 语言基础学习

主要也是自己读书的一点笔记吧

0x01 前言

当时有一天在地铁上看微信读书的时候想起来:噢对我是时候写一点关于 Go 的笔记了,所以就有了这篇 Go 语言基础学习的文章。

本文笔记基于 《Go 语言入门经典》

0x02 环境搭建

用 Goland 搭建项目,每次创建项目之后,我们都需要对 Goland 进行一些配置,在 Goland 的右上方找到“Add Configuration”并单击。

选择 Directory,接着写 helloWorld 文件

1
2
3
4
5
6
7
package main  

import "fmt"

func main() {
fmt.Println("Hello World")
}

0x03 GO 语言基础

1. 类型

字符串类型

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func sayHello(s string) string {
return "Hello " + s
}

func main() {
fmt.Println(sayHello("Drunkbaby"))
}

int 类型

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func addition(x int, y int) int {
return x+y
}

func main() {
fmt.Println(addition(2,4))
}

bool 类型

1
2
3
4
5
6
7
8
9
10
package main  

import "fmt"

func main() {
var b bool
fmt.Println(b)
b = true
fmt.Println(b)
}

数值类型

int:平平无奇

float:氛围 float32 与 float64,一般用 float64 居多

定义如下

1
var f float64 = 0.111

类型转换

  • 此处提及两个包,一个是 reflect,一个是 srtconv
1
2
3
4
5
6
7
8
9
10
11
12
package main  

import (
"fmt"
"reflect" "strconv")

func main() {
var b bool = true
fmt.Println(reflect.TypeOf(b))
var s string = strconv.FormatBool(true)
fmt.Println(reflect.TypeOf(s))
}

2. 变量

字符串变量

1
2
3
4
5
6
7
8
package main  

import "fmt"

func main() {
var s string = "Hello World"
fmt.Println(s)
}

快捷声明变量

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
var (
s string = "Drunkbaby"
i int = 4
)
fmt.Println(s)
fmt.Println(i)
}

声明变量后,就不能再次声明它,不然会报错。

变量零值

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

编写简短变量

:= 符号是简短变量声明

1
2
3
4
5
6
7
8
package main  

import "fmt"

func main() {
s := "Hello World"
fmt.Println(s)
}

简短变量声明是最常用的变量声明方式,还有一些比较简洁的变量声明

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

var s = "Hello World"

func main() {
i := 42
fmt.Println(s)
fmt.Println(i)
}

有关作用域

和其他语言是一样的,大括号作为作用域的分割,看代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main  

import "fmt"

var s2 = "Hello World"

func main() {
fmt.Printf("Print 's2' variable from outer block %v\n", s2)
b := true
if b {
fmt.Printf("Printing 'b' variable from outer block %v\n", b)
i := 42
if b != false {
fmt.Printf("Printing 'i' variable from outer block %v\n", i)
}
}
}

指针

1
2
3
4
5
6
7
8
package main  

import "fmt"

func main() {
s := "Hello World"
fmt.Println(&s)
}

输出一个十六进制的内存地址

将变量作为值传递时,地址不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main  

import "fmt"

func showMemoryAddress(x *int) {
fmt.Println(x)
return
}

func main() {
i := 1
fmt.Println(&i)
showMemoryAddress(&i)
}

如果要使用指针指向变量的值,而非内存地址,应当在指针变量前加上星号。

1
2
3
4
func showMemoryAddress(x *int)  {  
fmt.Println(*x)
return
}

声明常量

1
2
3
4
5
6
7
8
9
10
package main  

import "fmt"

const greeting string = "Hello World"

func main() {
greeting = "Goodbye, fuck security"
fmt.Println(greeting)
}

const 常量无法被修改,所以会报错

3. 函数

返回多个值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main  

import "fmt"

func getPrize() (int, string) {
i := 2
s := "Drunkbaby"
return i, s
}

func main() {
quantity, prize := getPrize()
fmt.Printf("You won %v %v\n", quantity, prize)
}

不定参数函数

很有意思,是用三个点的,变量 numbers 是一个包含所有参数的切片。

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

func sumNumbers(numbers... int) int {
total := 0
for _, number := range numbers {
total += number
}
return total
}

func main() {
result := sumNumbers(1, 2, 3, 4)
fmt.Printf("The result is %v\n", result)
}

具名返回值

按照声明顺序返回具体名称变量值。

1
2
3
4
5
6
7
8
9
10
11
12
13
package main  

import "fmt"

func sayHi() (x, y string) {
x = "hello"
y = "world"
return
}

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

递归函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main  

import "fmt"

func feedMe(portion int, eaten int) int {
eaten = portion + eaten
if eaten >= 5 {
fmt.Printf("I'm full! I've eaten %d\n", eaten)
return eaten
}
fmt.Printf("I'm still hungry! I've eaten %d\n", eaten)
return feedMe(portion, eaten)
}

func main() {
feedMe(1, 0)
}

将函数作为值传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main  

import "fmt"

func anotherFunction(f func() string) string {
return f()
}

func main() {
fn := func() string {
return "function called"
}
fmt.Println(anotherFunction(fn))
}

4. 控制流程

if

1
2
3
4
5
6
7
8
9
10
package main  

import "fmt"

func main() {
b := true
if b {
fmt.Println("b is true!")
}
}

else

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
b := false
if b {
fmt.Println("b is true")
} else {
fmt.Println("b is false")
}
}

elseif

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
i := 3
if i == 3 {
fmt.Println("i is 3")
} else if i == 2 {
fmt.Println("i is 2")
}
}

运算符

  • 算术运算符
  • 逻辑运算符

switch,可以说是 if 的高级用法了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

func main() {
i := 2

switch i {
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
case 4:
fmt.Println("Four")
}
}

default in switch 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

func main() {
s := "c"

switch s {
case "a":
fmt.Println("The letter is a!")
case "b":
fmt.Println("The letter is b!")
default:
fmt.Println("I don't recognize that letter")
}
}

for 循环

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func main() {
i := 0
for i < 10 {
i++
fmt.Println("i is", i)
}
}

简化写法,也是最常规的写法

1
2
3
4
5
6
7
8
9
package main  

import "fmt"

func main() {
for i := 0; i < 10; i++ {
fmt.Println("i is", i)
}
}

包含 range 子句的 for 语句

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func main() {
numbers := []int{1,2,3,4}
for i, n := range numbers {
fmt.Println("The index of the loop is", i)
fmt.Println("The value from the array is", n)
}
}

defer 语句

defer 是一个很有用的 Go 语言功能,它能够让程序在函数返回前执行另一个函数。函数在遇到 return 语句或到达函数末尾的时候返回。defer 语句通常用于执行清理操作或确保操作。

1
2
3
4
5
6
7
8
package main  

import "fmt"

func main() {
defer fmt.Println("I am run after the function completes")
fmt.Println("Hello World")
}
  • 在执行完 main 函数后执行 defer 函数

5. 数组、切片和映射

数组的相关基础操作

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
var cheeses [2]string
cheeses[0] = "Silly"
cheeses[1] = "Drunkbaby"
fmt.Println(cheeses[0])
fmt.Println(cheeses[1])
fmt.Println(cheeses)
}

声明数组的变量之后,就不能给它再添加元素了,比如此处我想 cheeses[2]="boy" 就会报错

切片

一些书面语比较难以理解,我们可以讲的简易一些,切片≈数组

切片是底层数组中的一个连续片段,,通过它可以访问该数组中一系列带编号的元素,因此,切片可以让我们访问数组的特定部分,比较像索引吧。

在切片中添加元素

其实我并不喜欢这种说法,更像是给数组增加元素。

用的方法是直接 append,,很有意思,不像 Java 里面是 xxx.append(),可以同时添加多个元素

1
2
3
4
5
6
7
8
9
10
11
package main  

import "fmt"

func main() {
var cheeses = make([]string, 2)
cheeses[0] = "Silly"
cheeses[1] = "Drunkbaby"
cheeses = append(cheeses, "Boy", "too", "silly")
fmt.Println(cheeses)
}
从切片中删除元素

也是用 append

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main  

import "fmt"

func main() {
var cheeses = make([]string, 3)
cheeses[0] = "Silly"
cheeses[1] = "Drunkbaby"
cheeses[2] = "Baby"
fmt.Println(len(cheeses))
fmt.Println(cheeses)
cheeses = append(cheeses[:2], cheeses[2+1:]...)
fmt.Println(len(cheeses))
fmt.Println(cheeses)
}
切片元素复制

用的是 copy

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
var cheeses = make([]string, 2)
cheeses[0] = "Silly"
cheeses[1] = "Drunkbaby"
var smeelyCheeses = make([]string, 2)
copy(smeelyCheeses, cheeses)
fmt.Println(smeelyCheeses)
}

映射

映射读起来比较别扭,比较像 Java 里面的 Map,也就是键值对

  • 创建空映射
1
var players= make(map[stringint)

对应的放 key value 并不是用 put 方法,而是如此

1
2
3
players["cook"] = 32
players["bairstow"] = 27
players["stokes"] = 26
从映射中删除元素
1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
var players = make(map[string]int)
players["cook"] = 32
players["bairstow"] = 27
players["stokes"] = 26
delete(players, "cook")
fmt.Println(players)
}

6. 结构体与指针

一个基础的结构体

结构体与类差不多,概念方面不再赘述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

type Movie struct {
Name string
Rating float32
}

func main() {
m := Movie{
Name: "Drunkbaby",
Rating: 10,
}
fmt.Println(m.Name, m.Rating)
}

“实例化一个 struct 实例”

  • 和 new 一个 class 一样,比较简单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

type Person struct {
Name string
Rating float32
}

func main() {
var m Person
fmt.Printf("%+v\n", m)
m.Name = "Drunkbaby"
m.Rating = 10
fmt.Printf("%+v\n", m)
}

“new 一个 struct 实例”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main  

import "fmt"

type Student struct {
Name string
Age float32
}

func main() {
m := new(Student)
m.Name = "Drunkbaby"
m.Age = 10
fmt.Printf("%+v\n", m)
}

嵌套结构体

结构体内包含结构体

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
27
28
package main  

import "fmt"

type Superhero struct {
Name string
Age int
Address Address
}

type Address struct {
Number int
Street string
City string
}

func main() {
e := Superhero{
Name: "Batman",
Age: 32,
Address: Address{
Number: 1007,
Street: "Mountain Drive",
City: "Gotham",
},
}
fmt.Printf("%+v\n", e)
}

结构体的构造函数

  • 简单。。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main  

import "fmt"

type Alarm struct {
Time string
Sound bool
}

func NewAlarm(time string) Alarm {
a := Alarm{
Time: time,
Sound: true,
}
return a
}

func main() {
fmt.Printf("%+v\n", NewAlarm("07:00"))
}

结构体进行比较

这个挺有意思哈哈

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"

type Drink struct {
Name string
Ice bool
}

func main() {
a := Drink{
Name: "Lemonade",
Ice: true,
}
b := Drink{
Name: "Lemonade",
Ice: true,
}
if a == b {
fmt.Println("a and b are the same")
}
fmt.Printf("%+v\n", a)
fmt.Printf("%+v\n", b)
}

检查结构体类型

在 go 里面用的是 reflect,挺有意思的,在 Java 里面这也被称作反射,不愧是反射,能够看到结构体是什么

1
2
fmt.Println(reflect.TypeOf(a))  
fmt.Println(reflect.TypeOf(b))

区分指针引用和值引用

  • 这就是老师特别喜欢讲的,变了一个,另外一个会不会变

先说结论
值引用,两个无关联
指针引用,一个变另外一个跟着变

值引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main  

import "fmt"

type work struct {
Name string
isWork bool
}

func main() {
a := work{
Name: "Fire",
isWork: true,
}
b := a
b.isWork = false
fmt.Printf("%+v\n", b)
fmt.Printf("%+v\n", a)
fmt.Printf("%p\n", &a)
fmt.Printf("%p\n", &b)
}

指针引用

两个一起变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main  

import "fmt"

type Teacher struct {
Name string
isWorking bool
}

func main() {
a := Teacher{
Name: "Drunkbaby",
isWorking: true,
}
b := &a
b.isWorking = false
fmt.Printf("%+v\n", *b)
fmt.Printf("%+v\n", a)
fmt.Printf("%p\n", b)
fmt.Printf("%p\n", &a)
}

将指向的指针(而不是本身)赋给 ,这是使用和号字符表示的。由于 b 是指针,因此必须使用星号字符对其进行引用

7. 创建方法与接口

方法,也就是类的函数,和 Java 当中的 “方法”是一样的,那么在 Go 中需要如何定义呢?

比如我有一个类(结构体),代码如下

1
2
3
4
5
6
7
8
9
10
package main  

type Movie struct {
Name string
Rating float64
}

func (m *Movie) summary() string {
return "1"
}

需要我们在方法名前,加入 m *struct 才可以

声明与调用方法

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"
"strconv")

type Movie struct {
Name string
Rating float64
}

func (m *Movie) summary() string {
r := strconv.FormatFloat(m.Rating, 'f', 1, 64)
return m.Name + ", " + r
}

func main() {
m := Movie{
Name: "SpiderMan",
Rating: 3.2,
}

fmt.Println(m.summary())
}

当然一个类可以有多个方法

值传递与指针传递

  • 方法传参,就是很平常。
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
27
28
29
package main  

import "fmt"

type Triangle struct {
base float64
height float64
}

func (t Triangle) changeBase(f float64) {
t.base = f
return
}

func (t *Triangle) changeBasePointer(f float64) {
t.base = f
return
}

func main() {
t := Triangle{
base: 3,
height: 1,
}
t.changeBase(4)
fmt.Println(t.base)
t.changeBasePointer(4)
fmt.Println(t.base)
}
  • 如果需要修改原始结构体,就选指针。如果不需要修改原始结构体,就使用值。

接口

固定格式

1
2
3
4
5
type name interface {

}

// 在里面可以定义方法

我的理解是,接口里面定义方法,然后让具体的类去实现,但是这个类的实现就很微妙。。。。。。。。。。可以说基本没什么关联。无语

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package main  

import (
"errors"
"fmt")

type Robot interface {
PowerOn() error
}

type T850 struct {
Name string
}

func (a *T850) PowerOn() error {
return nil
}

type R2D2 struct {
Broken bool
}

func (r R2D2) PowerOn() error {
if r.Broken {
return errors.New("R2D2 is broken")
} else {
return nil
}
}

func Boot(r Robot) error {
return r.PowerOn()
}

func main() {
t := T850{
Name: "The Terminator",
}

r := R2D2{
Broken: true,
}

err := Boot(&r)

if err != nil {
fmt.Println(err)
} else {
fmt.Println("Robot is powered on")
}

err = Boot(&t)

if err != nil {
fmt.Println(err)
} else {
fmt.Println("Robot is powered on")
}
}

8. 字符串

一些基础的操作就不讲了,直接看一些我认为有意思的地方

使用缓冲区(stringBuffer)拼接字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main  

import (
"bytes"
"fmt")

func main() {
var buffer bytes.Buffer

for i := 0; i < 500; i++ {
buffer.WriteString("z")
}

fmt.Println(buffer.String())
}

原理同 Java

进制表示

小写

使用 ToLower() 接口

查找

使用 strings.Index(),如果找到,则输出第一个字串的索引开始;若找不到,则输出 -1

删除字符串中的空格

  • 删除前后空格
1
2
3
4
5
6
7
8
9
package main  

import (
"fmt"
"strings")

func main() {
fmt.Println(strings.TrimSpace(" I don't need all the space "))
}

9. Map 相关操作

Map 是 key-value 的键值对数据结构,类似于集合的意思

创建 map (但必须分配空间)

原本逻辑上声明 map,从 Java 的角度来说没什么问题

1
2
3
4
5
6
7
8
package main  

import "fmt"

func main() {
var a map[int]string
fmt.Println(a)
}

但是这个程序,我们是不能进行赋值的,原因是并没有给此 map,也就是变量 a 分配内存空间,如果我们尝试赋值,如下语句,是会报错的

1
a[1]="Drunkbaby"

那么要如何才能分配空间并赋值呢?这里我们创建一个空的 map 需要用 make,完整有效代码如下

1
2
3
4
5
6
7
8
9
10
11
12
package main  

import "fmt"

func main() {
// 创建空 map,却没有分配空间
var a map[int]string
// 在使用 map 前,需要先 make,make 的作用就是给 map 分配数据空间
a = make(map[int]string, 10)
a[1] = "Drunkbaby;"
fmt.Println(a)
}

同样可以自己赋值 a[2] = "silly"

但是再写 a[1] = "quan9i",那么之前的 a[1] = "Drunkbaby" 会被覆盖

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main  

import "fmt"

func main() {
// 创建空 map,却没有分配空间
var a map[int]string
// 在使用 map 前,需要先 make,make 的作用就是给 map 分配数据空间
a = make(map[int]string, 10)
a[1] = "Drunkbaby;"
a[2] = "cute"
a[1] = "quan9i"
fmt.Println(a)
}

结果如图,覆盖了 a[1],且是有序的

一般声明方式比较多的是这样

1
2
3
4
var cities = make(map[string]string)

// 或者是
cities := make(map[string]string)

简单练习案例

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
package main  

import "fmt"

// 练习案例
/*
课堂练习:演示一个 key-value 的 value 是 map 的案例
比如:我们要存放3个学生的信息,每个学生有 name 和 sex 信息
思路:map[string]map[string]string
*/

func main() {
studentMap := make(map[string]map[string]string)
studentMap["stu01"] = make(map[string]string, 2)
studentMap["stu01"]["name"] = "Drunkbaby"
studentMap["stu01"]["sex"] = "男"

studentMap["stu02"] = make(map[string]string, 2)
studentMap["stu02"]["name"] = "D1ng"
studentMap["stu02"]["sex"] = "女"

fmt.Println(studentMap["stu01"])
fmt.Println(studentMap["stu02"])
}
}

同样还可以这样取值

1
fmt.Println(studentMap["stu01"]["name"])

Map 的增删改查

增加和更新

根据 key 是否存在,如果 key 存在就是更新,不存在就是增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main  

import "fmt"

func main() {
cities := make(map[string]string)

cities["no1"] = "北京"
cities["no2"] = "上海"
cities["no3"] = "广州"

fmt.Println(cities)

cities["no3"] = "上海 ~"
fmt.Println(cities)
}

删除

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() {
cities := make(map[string]string)

cities["no1"] = "北京"
cities["no2"] = "上海"
cities["no3"] = "广州"

fmt.Println(cities)

// 演示删除
delete(cities, "no1")
fmt.Println(cities)
// 当 delete 指定的 key 不存在时,删除不会操作,也不会报错
delete(cities, "no4")
fmt.Println(cities)
}
  • 删除细节说明

如果要删除 map 当中所有的 key,有如下两种方法

1、遍历所有的 key,逐一删除
2、直接 make 一个新的空间,让老空间被 GC

Map 查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main  

import "fmt"

// 增加与更新

func main() {
cities := make(map[string]string)

cities["no1"] = "北京"
cities["no2"] = "上海"
cities["no3"] = "广州"

fmt.Println(cities)

key, flag := cities["no1"]
if flag {
fmt.Println("no1 的 key 为", key)
}
}

Map 的遍历

Map 的遍历不能简单的用 for 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main  

import "fmt"

// 增加与更新

func main() {
cities := make(map[string]string)

cities["no1"] = "北京"
cities["no2"] = "上海"
cities["no3"] = "广州"

for k, v := range cities {
fmt.Printf("k=%v v=%v\n", k, v)
}
}

和 python 基本上差不多

  • 那如果要遍历复杂的 Map 呢?就像我们之前讲的那一个案例,Map 套 Map
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"

// 遍历循环一个较为复杂的 Map
func main() {
studentMap := make(map[string]map[string]string)
studentMap["stu01"] = make(map[string]string, 2)
studentMap["stu01"]["name"] = "Drunkbaby"
studentMap["stu01"]["sex"] = "男"

studentMap["stu02"] = make(map[string]string, 2)
studentMap["stu02"]["name"] = "D1ng"
studentMap["stu02"]["sex"] = "女"

for k1, v1 := range studentMap {
fmt.Println(k1)
for k2, v2 := range v1 {
fmt.Printf("\t k2=%v v2=%v\n", k2, v2)
}
}
}

Map 的切片

还是比较重要的,但是确实很繁琐,最重要的是理解分配内存和 append 追加的思想

比如我们现在 make 一个长度为 2 的 Map,那么如果它满了之后,我们还需要追加数据,应该怎么操作呢?

答案是用 append() 函数,具体实现可以看代码,很好理解

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
27
28
29
package main  

import "fmt"

// Map 切片
/*
要求:使用一个 Map 来记录 monster 的信息 name 和 age 也就是说一个 monster 对应一个 map 并且妖怪的个数可以动态增加 => Map 切片
*/

func main() {
// 1、声明一个 map 切片
monsters := make([]map[string]string, 2)
// 2、增加一个妖怪的信息
monsters[0] = make(map[string]string)
monsters[0]["name"] = "牛魔王"
monsters[0]["age"] = "500"

monsters[1] = make(map[string]string)
monsters[1]["name"] = "玉兔精"
monsters[1]["age"] = "400"
fmt.Println(monsters)

newMonsters := map[string]string{
"name": "append 追加的妖怪",
"age": "200",
}
monsters = append(monsters, newMonsters)
fmt.Println(monsters)
}

Map 排序

新版本会自动根据 key 排序

Map 使用小结

1、使用前需要 make
2、map 是引用类型,在一个函数接收 map 后,如果修改,则会修改源数据中的 map
3、map 的 value 一般是 struct,更适合管理复杂的数据

第三点可能比较难理解,不过简单想一想就明白了

 评论