Day4.函数指针类型闭包_递归_map

一.slice扩容后内存地址确认

package main

import "fmt"

func testSliceMemAdd() {
    x := make([]int, 5)
    y := append(x, 1)
    fmt.Printf("x[0]=%v,%#v\n", &x[0], x)
    fmt.Printf("y[0]=%v,%#v\n", &y[0], y)
}

func main() {
    testSliceMemAdd()
}
// 扩容后将原先的切片从a拷贝到一个更大容量的切片 底层内存地址发生改变。
PS D:\project> .\bin\slice4.exe
x[0]=0xc000080030,[]int{0, 0, 0, 0, 0}
y[0]=0xc00005c050,[]int{0, 0, 0, 0, 0, 1}

二.指针类型

(1)指针相关操作

1.普通类型 变量存的就是值也叫值类型,指针类型存的是地址。
2.获取变量的地址,用&,比如:var a int,获取a的地址:&a
package main

import "fmt"

func main() {
    var a *int
    fmt.Printf("%p\n", a)  // 获取变量里面存储的值的地址
    fmt.Printf("%p\n", &a) // 获取变量的地址
}
3.指针类型,变量存的是一个地址,这个地址存的才是值。
b := 10
c := &b
fmt.Printf("%d\n", *c) // *c获取指针指向的地址的值

4.修改变量的值
func modify(a *int) {
    *a = 100
}

func main() {
    x := 200
    modify(&x)
    fmt.Printf("%v\n", x)

}

5.指针变量初始化
p = new(int)
*p = 100

三.内置函数

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: 用来做错误处理。

(一).new && make 区别

new_make_diff

func test3() {
    var a []int
    a = make([]int, 10)
    a[0] = 99
    fmt.Println(a)

    var p *[]int
    p = new([]int)
    /* (*p)[0] = 100 //指针指向一个切片 但是切片为空nil 未初始化 需要make初始化下*/
    *p = make([]int, 10)
    (*p)[0] = 199
    fmt.Println(p)
}

四.函数 (基础语法略)

修改数组的值

// 方法一
func modify_arr(a []int) {
    fmt.Printf("modify:%p\n", a)
    a[0] = 100

}

func test6() {
    var a [6]int
    fmt.Printf("%p\n", &a)
    modify_arr(a[:])
    fmt.Println(a)
}

// 方法二
func modify_arr(a *[6]int) {
    fmt.Printf("modify:%p\n", a)
    a[0] = 100

}

func test6() {
    var a [6]int
    fmt.Printf("%p\n", &a)
    modify_arr(&a)
    fmt.Println(a)
}

(一)golang函数特点

1. 不支持重载,一个包不能有两个名字一样的函数。
2. 函数是一等公民 函数也是一种类型 一个函数可以赋值给变量。
3. 匿名函数
4. 多返回值

(1).函数可以赋值给变量

package main

import "fmt"

func add(a, b int) int {
    return a + b
}

func main() {
    c := add
    fmt.Printf("%p %T\n", c, add)

    sum := c(10, 20)
    fmt.Println(sum)

    sum = add(10, 20)
    fmt.Println(sum)
}

(2).函数也是一种类型

package main

import "fmt"

type add_func func(int, int) int

func add(a, b int) int {
    return a + b
}

func operator(op add_func, a int, b int) int {
    return op(a, b)
}

func main() {
    c := add
    sum := operator(c, 100, 200)
    fmt.Println(sum)
}

(二).函数参数传递方式

1.值传递
2.引用传递
注意1: 无论是值传递 还是引用传递 传递给函数的都是变量的副本,不过值传递是值的拷贝。
引用传递是地址的拷贝,一般来说地址拷贝更为高效。而值拷贝取决于拷贝的对象的大小,对象越大,则性能越低。

注意2: map/slice/chan/point/interface默认都是以引用的方式传递。
package main

import "fmt"

func modify(a *int) {
    *a = 100
}

func main() {
    a := 8
    fmt.Println(a)
    modify(&a)
    fmt.Println(a)
}

(三).命名返回值

/* 命名返回值 */
func calc(a, b int) (sum int, avg int) {
    sum = a + b
    avg = (a + b) / 2
    return
}


func main() {
    a := 8
    fmt.Println(a)
    modify(&a)
    fmt.Println(a)

    /* 命名返回值 */
    sum, avg := calc(999, 87295)
    fmt.Printf("sum=%d,avg=%d\n", sum, avg)

    /* 忽略返回值 */
    sum, _ = calc(999, 87295)
    fmt.Printf("sum=%d\n", sum)
}

(四).函数可变参数


/* 0个或者多个参数 arg是一个slice 我们可以通过arg[index]依次访问所有参数 通过len(arg)来判断传递参数的个数*/
func add(arg ...int) int {

}

/* 1个或者多个参数 */
func add(a int, arg ...int) int {

}

/* 2个或者多个参数 */
func add(a int, b int, arg ...int) int {

}
func funcArg(arg ...int) int {
    var sum int
    for i := 0; i < len(arg); i++ {
        sum = sum + arg[i]
    }
    return sum
}


func main() {
    fmt.Println(funcArg(1, 2, 3, 4, 5, 6, 7, 8, 9999999978))
}

(五).defer用途

1.当函数返回时 执行defer语句,因此 可以用来做资源清理。
2.多个defer语句,按照先进后出的方式执行 入栈。
3.defer语句中的变量,在defer声明时就决定了。
package main

import "fmt"

func testDefer() {
    i := 199
    fmt.Println("before", i)
    defer fmt.Println("defer1", i)

    if i > 199 {
        return
    }

    i = 299
    defer fmt.Println("defer2", i)
    fmt.Println("after", i)

}

func main() {
    testDefer()
}

(六).递归 一个函数调用自己 就叫递归。

func testRecusive(n int) int {
    if n == 1 {
        return 1
    }

    return testRecusive(n-1) * n
}
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·  
斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列",  
指的是这样一个数列:112358132134、……在数学上,  
斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)  

斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,   
144, 233377610987159725844181676510946177112865746368........这个数列从第3项开始,每一项都等于前两项之和。    


/* example */
func fab(n int) int {
    if n <= 3 {
        return 1
    }

    return fab(n-1) + fab(n-2)
}

func main() {
    for i := 0; i < 6; i++ {
        n := fab(i)
        fmt.Println(n)
    }
}

(七).闭包

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

package main

import (
    "fmt"
    "strings"
)

func makeSuffixFunc(suffix string) func(string) string {
    return func(name string) string {
        if !strings.HasSuffix(name, suffix) {
            return name + suffix
        }
        return name
    }
}

func main() {
    func1 := makeSuffixFunc(".jpg")
    func2 := makeSuffixFunc(".png")

    fmt.Println(func1("jesse"))
    fmt.Println(func2("maggie"))
}

五.排序和查找操作

1.sort.Ints 对证书进行排序。
2.sort.Strings对字符串进行排序。
3.sort.Float64s对浮点数进行排序。

sort.SearchInts(a []int,b int) // 从数组a中查找b 前提是a不许有序
sort.SearchFloat64s(a []float64,b float64)
sort.SearchStrings(a []string,b string)

六.map数据结构

(一).key-value的数据结构,又叫字典或关联数组。

声明(声明时不会分配内存,初始化需要make)

var map1 map[key_type]value_type
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string

map相关操作

vara 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) // 长度

(二).map数据结构

1.map是引用类型

package main

import "fmt"

func testMap() {
    var a map[string]int
    a = make(map[string]int, 10)
    a["a1"] = 200
    a["a2"] = 201

    for k, v := range a {
        fmt.Printf("key[%s]=value[%d]\n", k, v)
    }

    // 判断key是否存在,如果存在则打印出对应的value
    val, ok := a["a3"]
    if ok {
        fmt.Printf("val=%d\n", val)
    } else {
        fmt.Println("not found")
    }
}

func sliceOfMap() {
    items := make([]map[int]int, 5)
    for i := 0; i < len(items); i++ {
        items[i] = make(map[int]int)
    }

    items[0][0] = 100
    fmt.Println(items)
}

func main() {
    // testMap()
    sliceOfMap()
}

(三).map排序(map里面的key是无序的)

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

排序示例:

package main

import (
    "fmt"
    "sort"
    "strings"
)

func line() {
    fmt.Println(strings.Repeat("-", 100))
}

func sortMap() {
    var a map[string]int
    a = make(map[string]int, 10)
    a["abc"] = 1
    a["dfs"] = 100
    a["bcd"] = 999
    a["hello"] = 1010
    a["world"] = 2020

    fmt.Println(a)
    var keys []string
    line()
    for k, v := range a {

        keys = append(keys, k)
        fmt.Printf("a[%s]=%d\n", k, v)
    }
    line()
    sort.Strings(keys)
    for _, k1 := range keys {
        fmt.Printf("key[%s]=%v\n", k1, a[k1])
    }
}

func main() {
    sortMap()
}

result:

PS D:\project> .\bin\sortMap.exe
map[abc:1 bcd:999 dfs:100 hello:1010 world:2020]
-------------------------------------------------------------------------
a[dfs]=100
a[world]=2020
a[abc]=1
a[bcd]=999
a[hello]=1010
-------------------------------------------------------------------------
key[abc]=1
key[bcd]=999
key[dfs]=100
key[hello]=1010
key[world]=2020
PS D:\project>

七.实战练习

1.实现一个冒泡排序
2.实现一个选择排序
3.实现一个插入排序
4.实现一个快速排序

bubbleSort.go

package main

import "fmt"

/*
38 1 4 5 10
1 38 4 5 10
1 4 38 5 10
1 4 5 38 10
1 4 5 10 38
*/

func bubbleSort(x []int) {
    for i := len(x) - 1; i > 0; i-- {
        for j := 0; j < i; j++ {
            if x[j] > x[j+1] {
                x[j], x[j+1] = x[j+1], x[j]
            }
        }
    }

}

func main() {
    x := []int{1, 99, 23, 879, 213, 31}
    bubbleSort(x)
    fmt.Println(x)
}
Copyright © zhangluya.com 2019            UPDATE 2020-03-26 15:42:33

results matching ""

    No results matching ""