GO语言系列(四)- 内置函数、闭包与高级数据类型

一、内置函数、递归函数、闭包

内置函数

  • 1. close:主要用来关闭channel
  • 2. len:用来求长度,比如string、array、slice、map、channel
  • 3. new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
  • 4. make:用来分配内存,主要用来分配引用类型,比如chan、map、slice
  • 5. append:用来追加元素到数组、slice中
  • 6. panic和recover:用来做错误处理
  • 7. new和make的区别

package main

import (
    "errors"
    "fmt"
)

func initConfig() (err error) {
    return errors.New("init config failed")
}

func test() {
    /*
        defer func() {
            if err := recover(); err != nil {
                fmt.Println(err)
            }
        }()
    */
    err := initConfig()
    if err != nil {
        panic(err)
    }
    return
}

func main() {
    test()
    var i int
    fmt.Println(i)  // 0
    fmt.Println(&i) // 0xc0000100a8

    j := new(int)
    *j = 100
    fmt.Println(j)  // 0xc00005a088
    fmt.Println(*j) // 100

    var a []int // 定义slice
    a = append(a, 10, 20, 354)
    a = append(a, a...) // ...可变参数   slice展开
    fmt.Println(a)
}
内置函数案例
package main

import "fmt"

func test() {
    s1 := new([]int)
    fmt.Println(s1)

    s2 := make([]int, 10)
    fmt.Println(s2)

    *s1 = make([]int, 5)
    (*s1)[0] = 100
    s2[0] = 100
    fmt.Println(s1)
    fmt.Println(s2)
    return
}

func main() {
    test()
}
内置函数2

递归函数

  • 1. 一个函数调用自己,就叫做递归。

  • 2. 递归设计原则

1)一个大的问题能够分解成相似的小问题

2)定义好出口条件

 案例:递归输出hello,实现阶乘,实现斐波那契数

package main

import (
	"fmt"
	"time"
)

// 递归
func recusive(n int) {
	fmt.Println("hello", n)
	time.Sleep(time.Second)
	if n > 10 {
		return
	}
	recusive(n + 1) // 至少上百万上千万次递归
}

// 阶乘
func factor(n int) int {
	if n == 1 {
		return 1
	}
	return factor(n-1) * n
}

//斐波那契数
func fab(n int) int {
	if n <= 1 {
		return 1
	}
	return fab(n-1) + fab(n-2)
}

func main() {
	// fmt.Println(factor(5))
	recusive(0)
	// for i := 0; i < 10; i++ {
	// fmt.Println(fab(i))
	// }
}

 闭包

闭包:一个函数和与其相关的引用环境组合而成的实体

案例:Adder和为文件名添加后缀

package main

import (
	"fmt"
	"strings"
)

func Adder() func(int) int {
	var x int
	return func(d int) int {
		x += d
		return x
	}
}

func makeSuffix(suffix string) func(string) string {
	return func(name string) string {
		if strings.HasSuffix(name, suffix) == false {
			return name + suffix
		}
		return name
	}
}

func main() {
	f := Adder()
	fmt.Println(f(1))
	fmt.Println(f(100))
	fmt.Println(f(1000))

	f1 := makeSuffix(".bmp")
	fmt.Println(f1("test"))
	fmt.Println(f1("pic"))

	f2 := makeSuffix(".jpg")
	fmt.Println(f2("test"))
	fmt.Println(f2("pic"))
}

二、数组和切片

数组

  • 1. 数组:是同一种数据类型的固定长度的序列。
  • 2. 数组定义:var a [len]int,比如:var a[5]int,一旦定义,长度不能变
  • 3. 长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型
  • 4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1
for i := 0; i < len(a); i++ {
}
for index, v := range a {
}
  • 5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic
  • 6. 数组是值类型,因此改变副本的值,不会改变本身的值
package main

import "fmt"

func test1() {
    var a [10]int
    a[0] = 10
    a[9] = 100
    fmt.Println(a)

    for i := 0; i < len(a); i++ {
        fmt.Println(a[i])
    }
    for index, val := range a {
        fmt.Printf("a[%d]=%d\n", index, val)
    }
}

func test2() {
    var a [10]int
    b := a
    b[0] = 100
    fmt.Println(a)
}

func test3(arr *[5]int) {
    (*arr)[0] = 1000
}

func main() {
    test1()
    test2()
    var a [5]int
    test3(&a)
    fmt.Println(a)
}

/*
[10 0 0 0 0 0 0 0 0 100]
10
0
0
0
0
0
0
0
0
100
a[0]=10
a[1]=0
a[2]=0
a[3]=0
a[4]=0
a[5]=0
a[6]=0
a[7]=0
a[8]=0
a[9]=100
[0 0 0 0 0 0 0 0 0 0]
[1000 0 0 0 0]
*/
数组示例一

数组初始化

a. var age0 [5]int = [5]int{1,2,3}
b. var age1 = [5]int{1,2,3,4,5}
c. var age2 = […]int{1,2,3,4,5,6}
d. var str = [5]string{3:”hello world”, 4:”tom”}

多维数组

a. var age [5][3]int
b. var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}  

多维数组遍历

package main

import (
	"fmt"
)

func main() {

	var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}

	for k1, v1 := range f {
		for k2, v2 := range v1 {
			fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
		}
		fmt.Println()
	}
} 

数组示例

package main

import (
    "fmt"
)

func fab(n int) {
    var a []int
    a = make([]int, n)

    a[0] = 1
    a[1] = 1

    for i := 2; i < n; i++ {
        a[i] = a[i-1] + a[i-2]
    }

    for _, v := range a {
        fmt.Println(v)
    }
}

func testArray() {
    var a [5]int = [5]int{1, 2, 3, 4, 5}
    var a1 = [5]int{1, 2, 3, 4, 5}
    var a2 = [...]int{38, 283, 48, 38, 348, 387, 484}
    var a3 = [...]int{1: 100, 3: 200}
    var a4 = [...]string{1: "hello", 3: "world"}

    fmt.Println(a)
    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)
    fmt.Println(a4)
    /*
        [1 2 3 4 5]
        [1 2 3 4 5]
        [38 283 48 38 348 387 484]
        [0 100 0 200]
        [ hello  world]
    */
}

func testArray2() {
    var a [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}

    for row, v := range a {
        for col, v1 := range v {
            fmt.Printf("(%d,%d)=%d ", row, col, v1)
        }
        fmt.Println()
    }
}

func main() {
    fab(10)
    testArray()
    testArray2()
}
数组示例二

切片

1. 切片相关概念

  • 1. 切片:切片是数组的一个引用,因此切片是引用类型
  • 2. 切片的长度可以改变,因此,切片是一个可变的数组
  • 3. 切片遍历方式和数组一样,可以用len()求长度
  • 4. cap可以求出slice最大的容量,0 <= len(slice) <= (array),其中array是slice引用的数组
  • 5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int

2. 切片的相关语法

  • 1. 切片初始化:var slice []int = arr[start:end] 包含start到end之间的元素,但不包含end
  • 2. Var slice []int = arr[0:end]可以简写为 var slice []int=arr[:end]
  • 3. Var slice []int = arr[start:len(arr)] 可以简写为 var slice[]int = arr[start:]
  • 4. Var slice []int = arr[0, len(arr)] 可以简写为 var slice[]int = arr[:]
  • 5. 如果要切片最后一个元素去掉,可以这么写: Slice = slice[:len(slice)-1]

3. 切片的内存布局

4. 通过make来创建切片

var slice []type = make([]type, len)
slice := make([]type, len)
slice := make([]type, len, cap)

5. 用append内置函数操作切片

slice = append(slice, 10)
var a = []int{1,2,3}
var b = []int{4,5,6}
a = append(a, b…)

6. For range 遍历切片

for index, val := range slice {
}

7. 切片resize

var a = []int {1,3,4,5}
b := a[1:2]
b = b[0:3]

8. 切片拷贝

s1 := []int{1,2,3,4,5}

s2 := make([]int, 10)

copy(s2, s1)

s3 := []int{1,2,3}

s3 = append(s3, s2…)

s3 = append(s3, 4,5,6)

9. string与slice

  string底层就是一个byte的数组,因此,也可以进行切片操作

str := “hello world”
s1 := str[0:5]
fmt.Println(s1)
s2 := str[5:]
fmt.Println(s2)

10. string的底层布局

11. 如何改变string中的字符值?

string本身是不可变的,因此要改变string中字符,需要如下操作:

str := “hello world”
s := []byte(str)
s[0] = ‘o’
str = string(s)

12. 排序和查找操作

排序操作主要都在 sort包中,导入就可以使用了

sort.Ints对整数进行排序, sort.Strings对字符串进行排序, sort.Float64s对
浮点数进行排序.
sort.SearchInts(a []int, b int) 从数组a中查找b,前提是a必须有序
sort.SearchFloats(a []float64, b float64) 从数组a中查找b,前提是a必须有序
sort.SearchStrings(a []string, b string) 从数组a中查找b,前提是a必须有序

示例

package main

import "fmt"

type slice struct {
    ptr *[100]int
    len int
    cap int
}

func make1(s slice, cap int) slice {
    s.ptr = new([100]int)
    s.cap = cap
    s.len = 0
    return s
}

func testSlice() {
    var slice []int
    var arr [5]int = [...]int{1, 2, 3, 4, 5}

    slice = arr[:]
    fmt.Println(slice)
    fmt.Println(arr[2:4]) // [3,4]
    fmt.Println(arr[2:])  // [3,4,5]
    fmt.Println(arr[0:1]) // [1]
    fmt.Println(arr[:len(arr)-1])
}

func modify(s slice) {
    s.ptr[1] = 1000
}

func testSlice2() {
    var s1 slice
    s1 = make1(s1, 10)

    s1.ptr[0] = 100
    modify(s1)

    fmt.Println(s1.ptr)
}

func modify1(a []int) {
    a[1] = 1000
}

func testSlice3() {
    var b []int = []int{1, 2, 3, 4}
    modify1(b)
    fmt.Println(b)
}

func testSlcie4() {
    var a = [10]int{1, 2, 3, 4}

    b := a[1:5]
    fmt.Printf("%p\n", b)     // 0xc000014238
    fmt.Printf("%p\n", &a[1]) // 0xc000014238
}

func main() {
    // testSlice()
    testSlice2()
    testSlice3()
    testSlcie4()
}
切片的用法示例一
package main

import "fmt"

func testSlice() {
    var a [5]int = [...]int{1, 2, 3, 4, 5}
    s := a[1:]
    fmt.Println("a:", a)
    s[1] = 100
    fmt.Printf("s=%p a[1]=%p\n", s, &a[1])
    fmt.Println("before a:", a)

    s = append(s, 10)
    s = append(s, 10)
    s = append(s, 10)
    s = append(s, 10)
    s = append(s, 10)

    s[1] = 1000
    fmt.Println("after a:", a)
    fmt.Println(s)
    fmt.Printf("s=%p a[1]=%p\n", s, &a[1])
}

func testCopy() {
    var a []int = []int{1, 2, 3, 4, 5}
    b := make([]int, 10)

    copy(b, a)

    fmt.Println(b)
}

func testString() {
    s := "hello world"
    s1 := s[0:5]
    s2 := s[6:]

    fmt.Println(s1)
    fmt.Println(s2)
}

func testModifyString() {
    s := "我hello world"
    s1 := []rune(s)

    s1[0] = 200
    s1[1] = 128
    s1[2] = 256
    str := string(s1)
    fmt.Println(str)
}

func main() {
    // testSlice()
    testCopy()
    testString()
    testModifyString()
}
切片的用法示例二
package main

import (
    "fmt"
    "sort"
)

func testIntSort() {
    var a = [...]int{1, 8, 43, 2, 456}
    sort.Ints(a[:])
    fmt.Println(a)
}

func testStrings() {
    var a = [...]string{"abc", "efg", "b", "A", "eeee"}
    sort.Strings(a[:])

    fmt.Println(a)
}

func testFloat() {
    var a = [...]float64{2.3, 0.8, 28.2, 392342.2, 0.6}
    sort.Float64s(a[:])
    fmt.Println(a)
}

func testIntSearch() {
    var a = [...]int{1, 8, 43, 2, 456}
    index := sort.SearchInts(a[:], 2)
    fmt.Println(index)
}

func main() {
    testIntSort()
    testStrings()
    testFloat()
    testIntSearch()
}
切片的用法示例三

三、map数据结构

1.map简介

key-value的数据结构,又叫字典或关联数组
a.声明

var map1 map[keytype]valuetype
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string

声明是不会分配内存的,初始化需要make

2. map相关操作

var a map[string]string = map[string]string{“hello”: “world”}
a = make(map[string]string, 10)
a[“hello”] = “world”	// 插入和更新
Val, ok := a[“hello”]	//查找
for k, v := range a {	//遍历
fmt.Println(k,v)
}
delete(a, “hello”)	// 删除
len(a)	// 长度

3. map是引用类型

func modify(a map[string]int) {
a[“one”] = 134
}

4. slice of map

Items := make([]map[int][int], 5)
For I := 0; I < 5; i++ {
items[i] = make(map[int][int])
}

5. map排序

a. 先获取所有key,把key进行排序
b. 按照排序好的key,进行遍历

6. Map反转

  • a. 初始化另外一个map,把key、value互换即可

 示例

package main

import "fmt"

func trans(a map[string]map[string]string) {
    for k, v := range a {
        fmt.Println(k)
        for k1, v1 := range v {
            fmt.Println("\t", k1, v1)
        }
    }
}

func testMap() {
    var a map[string]string = map[string]string{
        "key": "value",
    }
    // a := make(map[string]string, 10)
    a["abc"] = "efg"
    a["abc1"] = "wew"
    fmt.Println(a)
}

func testMap2() {
    a := make(map[string]map[string]string, 100)
    a["key1"] = make(map[string]string)
    a["key1"]["key2"] = "val2"
    a["key1"]["key3"] = "val3"
    a["key1"]["key4"] = "val4"
    a["key1"]["key5"] = "val5"
    a["key1"]["key6"] = "val6"
    fmt.Println(a)

}

func modify(a map[string]map[string]string) {
    _, ok := a["zhangsan"]
    if !ok {
        a["zhangsan"] = make(map[string]string)
    }
    a["zhangsan"]["pwd"] = "123456"
    a["zhangsan"]["nickname"] = "superman"
    return
}

func testMap3() {
    a := make(map[string]map[string]string, 100)
    modify(a)
    fmt.Println(a)
}

func testMap4() {
    a := make(map[string]map[string]string, 100)
    a["key1"] = make(map[string]string)
    a["key1"]["key2"] = "val2"
    a["key1"]["key3"] = "val3"
    a["key1"]["key4"] = "val4"
    a["key1"]["key5"] = "val5"
    a["key2"] = make(map[string]string)
    a["key2"]["key22"] = "val22"
    a["key2"]["key23"] = "val23"
    trans(a)
    delete(a, "key1")
    fmt.Println()
    trans(a)
}

func testMap5() {
    var a []map[int]int
    a = make([]map[int]int, 5)

    if a[0] == nil {
        a[0] = make(map[int]int)
    }
    a[0][10] = 10
    fmt.Println(a)
}

func main() {
    testMap()
    testMap2()
    testMap3()
    testMap4()
    testMap5()
}
map示例
package main

import (
    "fmt"
    "sort"
)

func testMapSort() {
    var a map[int]int
    a = make(map[int]int, 5)

    a[8] = 10
    a[3] = 10
    a[2] = 10
    a[1] = 10
    a[18] = 10

    var keys []int
    for k, _ := range a {
        keys = append(keys, k)
        // fmt.Println(k, v)
    }
    sort.Ints(keys)
    for _, v := range keys {
        fmt.Println(v, a[v])
    }
}

func testMapSort2() {
    var a map[string]int
    var b map[int]string

    a = make(map[string]int, 5)
    b = make(map[int]string, 5)
    a["8"] = 10
    a["3"] = 11
    a["2"] = 12
    a["1"] = 13
    a["18"] = 14

    for k, v := range a {
        b[v] = k
    }
    fmt.Println(b)
}

func main() {
    testMapSort()
    testMapSort2()
}
map示例2

四、包

1. golang中的包

  • a. golang目前有150个标准的包,覆盖了几乎所有的基础库

  • b. golang.org有所有包的文档,没事都翻翻

2. 线程同步

a. import(“sync”)
b. 互斥锁, var mu sync.Mutex
c. 读写锁, var mu sync.RWMutex
package main

import (
    "fmt"
    "math/rand"
    "sync"
    "sync/atomic"
    "time"
)

var rwLock *sync.RWMutex

func testLock() {

    var a map[int]int
    a = make(map[int]int, 5)

    a[8] = 10
    a[3] = 10
    a[2] = 10
    a[1] = 10
    a[18] = 10

    for i := 0; i < 2; i++ {
        go func(b map[int]int) {
            rwLock.RLock()
            b[8] = rand.Intn(100)
            rwLock.Unlock()
        }(a)
    }

    rwLock.RLock()
    fmt.Println(a)
    rwLock.Unlock()
}

func testRWLock() {
    // var rwLock myLocker = new(sync.RWMutex)
    // var rwLock sync.RWMutex
    // var rwLock sync.Mutex
    var a map[int]int
    a = make(map[int]int, 5)

    var count int32

    a[8] = 10
    a[3] = 10
    a[2] = 10
    a[1] = 10
    a[18] = 10

    for i := 0; i < 2; i++ {
        go func(b map[int]int) {
            rwLock.Lock()
            // lock.Lock()
            b[8] = rand.Intn(100)
            time.Sleep(time.Millisecond)
            rwLock.Unlock()
            // lock.Unlock()
        }(a)
    }

    for i := 0; i < 100; i++ {
        go func(b map[int]int) {
            for {
                rwLock.Lock()
                time.Sleep(time.Millisecond)
                // fmt.Println(a)
                rwLock.Unlock()
                atomic.AddInt32(&count, 1)
            }
        }(a)
    }

    time.Sleep(time.Second * 3)
    fmt.Println(atomic.LoadInt32(&count))
}

func main() {
    rwLock = new(sync.RWMutex)
    // testLock()
    testRWLock()
}
线程同步锁示例

3. go get安装第三方包

go get github.com/go-sql-driver/mysql

猜你喜欢

转载自www.cnblogs.com/zhangyafei/p/10659829.html
今日推荐