0%

Go零零碎碎

[TOC]

常见数据类型

值类型

值类型:基本数据类型int、float、bool、string、数组和结构体struct都属于值类型,使用这些类型的变量是直接使用指向存在内存中的值,值类型的变量的值通常存储在栈中

引用类型

引用类型:指针、slice切片、map、管道chan、interface等都是引用类型

字符串

golang的统一编码为utf-8,golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8,所以字母数字占一字节,汉字占3字节

要获取一个字符串的长度,有以下2种方式:

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"
"unicode/utf8"
)

func main() {
str := "hello 芝麻开门"
// 返回字符串的长度,相当于PHP的strlen
fmt.Println("str 的长度:", len(str))

fmt.Println("str 的RuneCountInString长度:", utf8.RuneCountInString(str))
fmt.Println("str 的rune convert长度:", len([]rune(str)))
/**
str 的长度: 18
str 的RuneCountInString长度: 10
str 的rune convert长度: 10
*/
}

golang中还有一个byte数据类型,与rune相似,它们都是用来表示字符类型的变量类型。它们的不同在于:

  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符
  • 循环一个字符串时,如果有中文,需要转切片,不然会出现乱码,因为是按照字符串的字节长度遍历
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
82
83
84
85
86
87
88
package main

import (
"fmt"
"unicode/utf8"
)

func main() {
str := "hello 芝麻开门"
// 返回字符串的长度,相当于PHP的strlen
fmt.Println("str 的长度:", len(str))

fmt.Println("str 的RuneCountInString长度:", utf8.RuneCountInString(str))
fmt.Println("str 的rune convert长度:", len([]rune(str)))
/**
str 的长度: 18
str 的RuneCountInString长度: 10
str 的rune convert长度: 10
*/
runeStr := []rune(str)
for i := 0; i < len(runeStr); i++ {
fmt.Printf("%c\n", runeStr[i])
}
/**
str 的长度: 18
str 的RuneCountInString长度: 10
str 的rune convert长度: 10
h
e
l
l
o





*/
// 字符串函数
// 判断一个字符串是否包含指定的字符串
fmt.Println(strings.Contains("hello world", "hello")) //true

// 统计一个字符串有几个指定的字符,判断字符重复次数
fmt.Println(strings.Count("hello world", "o")) // 2

// 字符串比较:不区分大小写==
fmt.Println(strings.EqualFold("hello world", "Hello World")) // true

// 返回一个字符串在另一个字符串第一次出现的index值
fmt.Println(strings.Index("hello world", "o")) // 4

// 返回一个字符串在另一个字符串最后一次出现的位置
fmt.Println(strings.LastIndex("hello world", "o")) // 7

// 字符串替换 n=-1表示全部替换
fmt.Println(strings.Replace("hello world", "hello", "你好", 1)) // 你好 world

// 查分字符串为数组,类似PHP中的explode
strArr := strings.Split("hello world", "o w")
fmt.Printf("strArr 类型 %T,值%v\n", strArr, strArr) // strArr 类型 []string,值[hell orld]
for i := 0; i < len(strArr); i++ {
fmt.Println(strArr[i])
/**
hell
orld
*/
}

// 对字符串大小写转换
fmt.Println(strings.ToLower("HELLO WORLD")) // hello world
fmt.Println(strings.ToUpper("hello world")) // HELLO WORLD

// 去除字符串两边的字符
fmt.Println(strings.TrimRight("~hello world~", "~")) // ~hello world
fmt.Println(strings.TrimLeft("~hello world~", "~")) // hello world~
fmt.Println(strings.Trim("~hello world~", "~")) // hello world

// 评断字符串头尾是否存在指定字符
fmt.Println(strings.HasPrefix("hello world", "hello")) // true
fmt.Println(strings.HasSuffix("hello world", "hello")) // false

// join联合组合字符串
fmt.Println(strings.Join(strArr, "o w")) // hello world

// 重复字符串
fmt.Println(strings.Repeat("go ", 3)) // go go go
}

数组

声明数组

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
func arrayDemo() {
// 定义并初始化一个长度为3的数组
var arr [3]int = [3]int{1, 2, 3}
arr1 := [3]int{1, 2, 3}
fmt.Println(arr, arr1) // [1 2 3] [1 2 3]

// 声明一个长度为6的数组,最后一个元素值为-1
arr2 := [...]int{5: -1}
fmt.Println(arr2) // [0 0 0 0 0 -1]

// 定义一个长度为3的int型数组,初始值是3个0,数组“零值”状态
var arr3 [3]int
fmt.Println(arr3) // [0 0 0]

// 二维数组
arr4 := [3][2]int{}
arr5 := [3][2]string{{"a", "b"}, {"AA", "BB"}, {"AAA", "BBB"}}
fmt.Println(arr4, arr5) // [[0 0] [0 0] [0 0]] [[a b] [AA BB] [AAA BBB]]

// 使用new声明数组
arr6 := new([3]int)
fmt.Printf("arr6类型%T,值%v", arr6, arr6) // arr6类型*[3]int,值&[0 0 0]

arr7 := new([2]int)
fmt.Printf("arr7类型%T,值%v" , arr7 , arr7) // arr7类型*[2]int,值&[0 0]
}

遍历数组

1
2
3
4
5
6
7
func for_range() {
arr := [...]string{"go", "php", "java"}
for key, value := range arr {
fmt.Printf("key = %v , value = %v", key, value)
// key = 0 , value = gokey = 1 , value = phpkey = 2 , value = java
}
}

slice切片

定义和创建

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"

func main() {
sliceDemo1()
sliceDemo2()
sliceDemo3()
}
func sliceDemo1() {
var arr [5]int = [...]int{1, 2, 3, 4, 5}
var slice = arr[1:3]
// slice value=[2 3] , cap=4 , len=2
fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice))
}
func sliceDemo2() {
var slice []int = make([]int, 5, 10)
fmt.Println(slice) // [0 0 0 0 0]
slice[1] = 5
slice[3] = 10
// slice value=[0 5 0 10 0] , cap=10 , len=5
fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice))
}
func sliceDemo3() {
// 声明和初始化一个切片
var slice []string = []string{"hello", "world", "!"}
fmt.Printf("slice value=%v , cap=%v , len=%v", slice, cap(slice), len(slice))
}

三种方式说明及区别

说明

sliceDemo1:让切片引用一个已经存在的数组创建切片

sliceDemo2:使用make来创建,可以指定切片的大小和容量,如果没有给切片赋值,则会使用默认值,(int、float=>0, strint=>””, bool=>false);make方式创建的切片对应的数组由make底层维护,对外不开见,只能通过slice访问各个元素

sliceDemo3:定义一个切片直接指定具体数组

区别

sliceDemo1方式是直接引用数组,这个数组是事先存在的,对程序员可见

sliceDemo2通过make创建切片,make也会创建一个数组,是由切片在底层维护,该数组对程序员不可见

冒泡排序

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

import "fmt"

func main() {
arr := [8]int{22, 31, 23, 44, 1, 55, 54, 33}
/**
[1 22 23 31 33 44 54 55]
[1 22 23 31 33 44 54 55]
[1 22 23 31 33 44 54 55]
**/
fmt.Println(bubble1(arr))
fmt.Println(bubble2(arr))
fmt.Println(bubble3(arr))
}
func bubble1(data [8]int) [8] int {
for i := 0; i < len(data)-1; i++ {
fmt.Println(data[i])
for j := 0; j < len(data)-1-i; j++ {
if data[j] > data[j+1] {
tmp := data[j]
data[j] = data[j+1]
data[j+1] = tmp
}
}
}
return data
}

func bubble2(data [8]int) [8]int {
for i := 0; i < len(data); i++ {
for j := i + 1; j < len(data); j++ {
if data[i] > data[j] {
tmp := data[i]
data[i] = data[j]
data[j] = tmp
}
}
}
return data
}
func bubble3(data [8]int) [8]int {
for i := 0; i < len(data); i++ {
for j := 0; j < len(data)-1; j++ {
if data[j] > data[j+1] {
tmp := data[j]
data[j] = data[j+1]
data[j+1] = tmp
}
}
}
return data
}

map

map相当于PHP中的关联数组

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"

func main() {
mapDemo()
}
func mapDemo() {
// 声明方式1
var map1 map[string]string
map1 = make(map[string]string, 5)
map1["name"] = "zhimma"
map1["address"] = "xian"
fmt.Println(map1) // map[name:zhimma address:xian]

// 声明方式2
map2 := make(map[string]string)
map2["name"] = "zhimma"
map2["address"] = "xian"
fmt.Println(map2) // map[name:zhimma address:xian]

// 声明方式3
map3 := map[string]string{
"name": "zhimma",
"address": "xian",
}
fmt.Println(map3) // // map[name:zhimma address:xian]
}

指针相关概念

变量:变量是基本类型,变量存的就是值,也叫值类型

地址:用于引用计算机的内存地址,可理解为内存地址的标签,通俗一点讲就是一个房子在小区门牌号

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

import "fmt"

func main() {
// 声明变量name并赋值
name := "zhimma"
fmt.Println("name 的地址是", &name) // name 的地址是 0xc000092030
}

指针:指针变量存的是一个地址,这个地址指向的空间存的才是值,指针是一个指向另一个变量内存地址的值

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"

func main() {
var i int = 1
fmt.Println("i 的地址是", &i)

var ptr *int = &i
fmt.Printf("ptr=%v\n", ptr)
fmt.Printf("ptr的地址是%v\n", &ptr)
fmt.Printf("ptr指向的值是%v\n", *ptr)
/**
i 的地址是 0xc00001a080

ptr=0xc00001a080
ptr的地址是0xc00000c030
ptr指向的值是1
*/
}

&:取地址符,指针 := &变量

*:取值符, 变量 := *指针

匿名函数

定义匿名函数有2种方式

  • 定义时直接使用(这种方式只使用一次)

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

    import "fmt"

    func main() {
    totalNum := func(a int, b int) int {
    return a + b
    }(5, 3)
    fmt.Println(totalNum) // 8
    }
  • 将匿名函数赋值给变量

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

    import "fmt"

    func main() {
    // 将匿名函数赋值给变量sunFunc
    sumFunc := func(a int, b int) int {
    return a + b
    }
    total := sumFunc(1, 2)
    fmt.Println(total)
    }
  • 全局匿名函数

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

    import "fmt"

    var globalFunc = func(params string) string {
    return "this is globalFunc and receive params str is'" + params + "'"
    }

    func main() {
    str := globalFunc("hello world")
    fmt.Println(str) // this is globalFunc and receive params str is'hello world'
    }

闭包

new函数

new函数用来分配内存,主要分配值类型,比如int、float32、struct等,返回的是指针

1
2
3
4
5
6
7
8
9
10
11
func newDemo() {
num := 100
fmt.Printf("num 的类型是%T,值是%v,地址是%v", num, num, &num)
// num 的类型是int,值是100,地址是0xc00001a178

num1 := new(int)
fmt.Printf("num1 的类型是%T,值是%v,地址是%v", num1, num1, &num1)
// num1 的类型是*int,值是0xc00001a190,地址是0xc00000c030
fmt.Printf("num1 的类型是%T,值是%v,地址是%v,指向的值是%v", num1, num1, &num1, *num1)
// num1 的类型是*int,值是0xc00001a098,地址是0xc00000c030,指向的值是0
}