13 Golang map集合

13 map集合

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

import "fmt"

/*
map是一个内建函数make可以使用map关键字来定义Map

定义map
方法一:
var map_variable map[key_data_type]value_data_type
方法二:
map_variable := make(map[key_data_type]value_data_type)

插入元素:
map_variable[new_key] = value

查找元素:
value, ok := map_variable[key]
如果存在ok为true,并且value为key所对应的值,如果不存在则为false

如果不初始化map,就会创建一个nil map, nil map 不能用来存放键值对

delete()函数:如果要删除的值不存在则不操作
delete(map_variable, key)
*/

func main() {
/*
//如果不初始化map,就会创建一个nil map, nil map 不能用来存放键值对
var dic map[int]string // 没有初始化
var dic = map[int]string{} // 初始化了,但是为空

dic[1] = "hello"
dic[2] = "hi"
dic[3] = "world"
*/
var dic = map[int]string{}

dic[1] = "hello"
dic[2] = "hi"
dic[3] = "world"

value, ok := dic[3]
if ok { // 如果存在
fmt.Println("vaule =", value)
}else {
fmt.Println("Not exist")
}
fmt.Println("map的值为:", dic)

delete(dic, 5) // 要删除的key不存在所以不操作

delete(dic, 3)
fmt.Println("map的值为:", dic)
}

14 Golang递归

14 递归

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

/*
Go语言的函数也可以递归调用
*/

// 如果返回值是一个参数则不需要带括号
// 如果是两个参数需要带括号
func Factorial(n int) int{
if n <= 1{
return 1
}
return n * Factorial(n - 1)
}

func main() {
var n = 20
fmt.Println("n的阶乘为:", Factorial(n))
fmt.Println("sizeof(n):", unsafe.Sizeof(n))
}

15 Golang类型转换

15 类型转换

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

import "fmt"

// refactor重构

/*
类型转换: 和C语言一样
typename()
*/

func main() {
var a = 97

b := string(a) // 成功
//c := float32(int(b)) // 失败

fmt.Println(b)
}

16 Golang接口

16接口

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

import "fmt"

// method 方法

/*
接口是一种数据类型,它把所有的具有共性的方法定义在一起,
任何其他类型只要实现了这些方法就是实现了这个接口。

接口的定义:
type interface_name interface{
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
*/

type Animal interface {
call() // 无参数,无返回值
eat() int // 无参数,有返回值
sleep(int) int // 有参数,有返回值
}


type Dog struct {
}

func (dog Dog) call(){
fmt.Println("汪汪")
}

func (dog Dog) eat() int{
return 1
}

func (dog Dog) sleep(n int) int{
fmt.Printf("sleep %d\n", n)
return n
}
func main() {

// 类似于C++的基类指针指向子类对象,接口的方法都需要实现
// 继承虚基类就要实现虚基类的所有方法
var dog Animal
dog = new(Dog)

fmt.Println(dog.eat())
dog.sleep(23)


}

17 Golang错误处理

17 错误处理

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 (
"errors"
"fmt"
)

/*
Go通过内置的错误接口提供了非常简单的错误处理机制

内部定义为:
type error interface {
Error() string
}
*/

// 内置的错误处理接口
func driv(a, b int)(float32, error) {
if b == 0{
return 0, errors.New("分母不能为0")
}
return float32(a)/float32(b), errors.New("success")
}

func main() {
result, err := driv(3, 4)
fmt.Println("result =", result, " err =", err)
}

19 Golang数组和切片

19 Go的数组和切片

且看官网文档:

参考链接

数组

  • 一维数组
    • 定义:var variable_name [SIZE] variable_type
    • 初始化:
      • var balance = [5]int{1, 2, 4, 5, 3}
      • var balance = []int{1, 2, 4, 5, 3}
    • 多维数组:var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type
  • 数组指针:var a * [3] int
  • 指针数组:var a [3] * int

切片

  • 定义

    • var identifier []type,切片不需要说明长度

    • var slical []type = make([]type, len)

    • slical := make([]make, len)

    • 指定切片的容量,可以不写,要求length <= capacity

      make ([]T, length, capacity)

区别

  • 数组是值类型;切片是引用类型
  • 数组做函数参数,拷贝一个数组传递;切片是指向一个数组切片的指针
  • 数组的长度也是Type的一部分;切片总是指向底层的数组的数据结构

代码论证

由于Go的数组

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

import (
"fmt"
"unsafe"
)

func main() {
var a = [3]int{1, 2, 3} // 数组
var b = a[:] // 切片
var c = a // 拷贝数组
var pa = &a[0]
var pb = &a[0]
var pc = &c[0]


fmt.Printf("a = %d, b = %d\n", &a, &b)
fmt.Printf("sizeof(a) = %d,sizeof(b) = %d\n", unsafe.Sizeof(a), unsafe.Sizeof(b))
fmt.Println("pa = &a[0] =", pa)
fmt.Println("pb = &b[0] =", pb)
fmt.Println("pc = &c[0] =", pc)

}
  • 运行结果
1
2
3
4
5
a = &[1 2 3], b = &[1 2 3]
sizeof(a) = 24,sizeof(b) = 24
pa = &a[0] = 0xc04200c2e0
pb = &b[0] = 0xc04200c2e0
pc = &c[0] = 0xc04200c300
  • 论证结果

    数组是值类型;切片是引用类型

21 Golang语言变量生命周期

21 Go语言变量生命周期

参考链接

https://blog.csdn.net/FX677588/article/details/78421334

生命周期

  • 函数中的局部变量被外部指针指向访问时候,这时这个变量会逃逸出函数,在堆上分配内存
  • 当用new申请的内存空间赋值给函数内的局部变量的时候(没有被外部指针指向),这时该
  • 代码
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"

var p * int

func main() {
tmp()

fmt.Println(" p =", p, " *p = ", *p)
}

func tmp() {

// 定义一个栈上的变量,查看地址空间
var base = 0
fmt.Println(" &base =", &base, " base =", base)

// i=num 会逃逸出函数,因为被外部的p指针指向访问了,在函数外仍然可以访问
var num int
num = 1
p = &num
fmt.Println("p = &num =", p, " *p =", *p)

// tp 不会逃逸出函数,因为没有外部变量指向访问
var tp = new(int)
*tp = 2
fmt.Println(" tp =", tp, " *tp =", *tp)
}

结果

本来打算在外面定义一个全局变量var itp int,用来存储new申请的内存空间的地址,然后把地址传递出去,再在main函数中做类型转换,访问这块内存空间,如果程序崩溃,则恰恰说明说明了tp没有逃逸出函数,思路如下:

itp = (int)tp ==> p2itp = (* int)itp

  • 第一个是拿到tp的内存地址空间,做类型转换的时候失败了编译器不允许这种操作,int32, int64, uint, uint32, uint64, uintptr都试过了也不行,通过这种方式拿到的地址没有产生指针指向访问所以变量的不会逃逸出函数
  • 第二个是拿到tp的值,再做类型转换,进行访问内存空间(读/写访问)如果程序崩溃掉了,则说明tp没有逃逸出函数
  • 不过上面的两步都不行,第一个虽然不能转换成功,但是可以通过fmt.Printf打印地址,可以得到地址值,然后再通过fmt.Scanf重新存储到变量itp中,但是第二步就不可以了,即使通过查内存的方式也无法验证,因为读取内存内容不一定引起程序的崩溃。必须通过读/写访问才可以完整的验证。

20 Golang数组指针VS指针数组

20 数组指针VS指针数组

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

import (
"fmt"
)

func main() {
var a = [3]int{1, 1, 1} // 数组

var i, j ,k int = 2, 2, 2
var c [3] * int = [3]* int {&i, &j, &k} // 指针数组,这是一个数组,里面存的都是指针
var d * [3] int = &a // 数组指针,这是一个指针,指向一个 [3]int 类型的数组
// 必须制定数组长度否则会 => cannot use &a (type *[3]int) as type *[]int in assignment

var e ** [3] int = &d // 数组指针的指针,指向一个 [3]int 类型的数组指针

fmt.Println("c[0] =", c[0], "c[1] =", c[1],"c[2] =", c[2])
fmt.Println("*c[0] =", *c[0], "*c[1] =", *c[1],"*c[2] =", *c[2])

fmt.Println("d =", d)
fmt.Println("*d =", *d)
fmt.Println("d[0] =", d[0], "d[1] =", d[1],"d[2] =", d[2])
fmt.Println("(*d)[0] =", (*d)[0], "(*d)[1] =", (*d)[1],"(*d)[2] =", (*d)[2])


fmt.Println("e =", e)
fmt.Println("*e =", *e)
fmt.Println("**e =", **e)
}

18 Golang批量修改文件后缀并格式化存储

18 批量修改文件后缀并格式化存储

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package main

import (
"fmt"
"io"
"os"
"path/filepath"
)

func main() {
dir := "C:/Users/Pip/Desktop/Go初识/"

// 改变路径
err := os.Chdir(dir)
if err != nil {
fmt.Println("打开文件失败")
os.Exit(1)
}

// 获取文件列表
fileList, err := filepath.Glob("*")
if err != nil {
fmt.Println("获取失败")
os.Exit(1)
}
fmt.Println(fileList)

// 遍历文件列表修改后缀并新建文件
for _, name := range fileList {
// 跳过.md文件
if string(name[len(name) - 3:]) == ".md"{
continue
}
newName := name[:len(name) - 3] + ".md"

// 打开.go文件
oldfile, err := os.OpenFile(name, os.O_RDWR, 0666)
if err != nil {
fmt.Printf("打开文件%s失败\n", newName)
os.Exit(1)
}
fmt.Println("Open file:", name, "success")

// 打开.md文件不存在则新建
newfile, err := os.OpenFile(newName, os.O_CREATE | os.O_RDWR, 0666)
if err != nil {
fmt.Printf("Open file: %s failed\n", newName)
os.Exit(1)
}
fmt.Println("Open file:", newName, "success")

// 修改格式写入另一个文件
_, err = newfile.WriteString("# " + name[:len(name)-3] + "\n```\n")
if err != nil{
fmt.Println("Write ", newName, "failed")
os.Exit(1)
}
var fileContent = make([] byte, 1024)
for ;;{
n, err := oldfile.Read(fileContent)
if err != nil && err != io.EOF{
fmt.Println("Write to", newName, "failed")
os.Exit(1)
}else if n == 0 {
break
}
newfile.WriteString(string(fileContent)[:n])
}
_, err = newfile.WriteString("\n```")
if err != nil {
fmt.Println("Write to", newName, "failed")
os.Exit(1)
}
fmt.Println("Write to", string(newName), "success\n")


//newfile.Sync() // 立即同步,即将内容写入数据
newfile.Close() // 关闭文件或者程序终止内容才会写入文件
}
}

06 Golang函数定义

06函数定义

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

import "fmt"

/* // 函数可以递归调用
* func function_name( [parameter list] ) [return_types] {
* // 函数体
* }
*
* 函数可以先使用后定义,这点与C语言不同,而且函数可以返回多个值
*/

// SDK软件开发工具包:Software Development Kit


func main(){
n := 6
fmt.Printf("斐波那契数列的第%d个数字为%d", n, fibo(n))

var arr = []int {2, 3, 32, 8, 1, 0, 12}
_max, _min := maxAndMin(arr, 7)
fmt.Println("\nmax = ", _max, "\nmin = ", _min)
}

func fibo(n int)int{
if n == 1 {
return 1
}else if n == 2 {
return 1
}else if n <= 0{
return 0
}
fi := fibo(n - 1) + fibo(n - 2)
return fi
}

func maxAndMin(arr [] int, n int)(int, int){
var _max, _min int

if n >= 2{
_min = arr[0]
_max = _min
}else if n == 1{
_min = arr[0]
_max = _min
}

for i := 1; i < n; i++{
if arr[i] > _max {
_max = arr[i]
}else if arr[i] < _min{
_min = arr[i]
}

}
return _max, _min
}