• GO-指针与函数


    一、指针类型

    1、普通类型,变量存的就是值,也叫值类型。指针类型存的是地址

    2、获取变量的地址,用&,比如:var a int, 获取a的地址 &a

    3、指针类型,变量存的是一个地址,这个地址存的才是值

    4、获取指针类型所指向的值,使用:* ,比如:var p *int,使用*p获取p指向的变量的值

    var a int = 5 

    var p *int = &a   0xefefefe 指向变量a的值是 5

    5、指针类型的变量初始话有两种:

    5.1、直接给指针赋值其他变量的地址

    func test3(){
        var p *int  //默认初始化nil
        var a int
        p = &a
        *p = 200
        fmt.Println(a)
    }

    5.2、使用new分配

    func test4(){
        var p *int
        p = new(int)
        *p = 2000
        fmt.Println(*p)
    }

    6、练习题

    6.1、练习1:写一个程序,获取一个变量的地址,并打印到终端

    package main
    import (
        "fmt"
    )
    func test1(){
        var a int = 5
        var p *int = &a
        fmt.Printf("a的地址是:%p ",p)
        fmt.Printf("a的值是:%d",*p)
    }
    func main(){
        test1()
    }
    运行打印的结果如下:

    6.2、练习2:写一个函数,传入一个int类型的指针,并在函数中修改所指向的值

    func modify(x *int){         //传入的变量x类型是指针 *int代表指针是整形的指针
        *x = 200                      //给x指针指向的值重新赋值为200
    }
    func test2(){
        var a int = 5             //定义一个整形的变量a,初始值是5
        var p *int = &a           //定义一个指针p,指向的是a
        fmt.Println("变量a的初始值是",a)   //打印a的初始值
        modify(p)                  //修改p指针指向的a的值
        fmt.Println("p指针指向的a变量的改变值是",a)   //打印a的值改变的结果

    }
    func main(){
        test2()
    }
     
    执行打印的结果如下:

    二、内置函数

    1、close:主要用来关闭channel

    2、len:用来求长度,比如string、array、slice、map、channel

    3、new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针。示例可以看上面一的5.2,

    4、make:用来分配内存,主要用来分配引用类型,比如channel、map、slice

    5、append:用来追加元素到数组、slice中

    6、panic和recover:用来做错误处理

    7、new和make的区别

    7.1、内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针

    7.2、内建函数 make 用来为 slice,map 或 chan 类型分配内存和初始化一个对象(注意:只能用在这三种类型上),跟 new 类似,第一个参数也是一个类型而不是一个值,跟 new 不同的是,make 返回类型的引用而不是指针,而返回值也依赖于具体传入的类型,具体说明如下:

       Slice: 第二个参数 size 指定了它的长度,它的容量和长度相同。
    你可以传入第三个参数来指定不同的容量值,但必须不能比长度值小。
    比如 make([]int, 0, 10)

      Map: 根据 size 大小来初始化分配内存,不过分配后的 map 长度为 0,如果 size 被忽略了,那么会在初始化分配内存时分配一个小尺寸的内存

      Channel: 管道缓冲区依据缓冲区容量被初始化。如果容量为 0 或者忽略容量,管道是没有缓冲区的

    7.3、总结:

      new 的作用是初始化一个指向类型的指针(*T),make 的作用是为 slice,map 或 chan 初始化并返回引用(T)。

    三、函数

    1、声明语法:func 函数名(参数列表)[(返回值列表)]{}

      func add(){

      }

      func add(a int,b int){

      }

      func add(a int, b int) int {

      }

      func add(a int, b int) (int , int){

      }

      func add(a , b int) (int , int){

      }

    2、golang函数的特点:

      a、不支持重载,一个包不能有两个名字一样的函数;

      b、函数是一等公民,函数也是一种类型,函数也可以赋值给变量

      c、匿名函数

      d、多返回值

      示例: 

      type add_func func(int, int)int

      func oprator(op add_func,a int,b int)int {
          //使用传进来的函数op,进行操作
          return op(a,b)
      }
      func add(a,b int) int {
          return a + b
      }  
      func main(){
          c:=add
          fmt.Println(c)
          sum := oprator(c,100,200)
          fmt.Println(sum)
     
      }
    3、函数参数传递方式:
      3.1、值传递
      3.2、引用传递
      注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本。值传递是值的拷贝,一般来说地址拷贝更高效。值拷贝取决于拷贝的对象的大小,对象越大,性能越低。
      注意2:map、slice、channel、指针、interface默认以引用的方式传递
    4、命名返回值的名字
    //重命名一个返回值
    func reduce(a , b int)(c int){
        c = a - b
        return
    }
    //重命名多个返回值
    func calc(a,b int)(sum int,avg int){
        sum = a + b
        avg = sum/2
        return
    }
    // _ 忽略返回值
    func main(){
        sum,_ := calc(100,200)
    }
    5、可变参数:
    多个参数
    func test11(arg...int) int{
    }
    一个或多个参数
    func test11(a int ,arg...int) int{
    }
    二个或多个参数
    func test11(a int,b int ,arg...int) int{
    }

    注意:其中arg是一个slice,我们可以通过arg[index]来获取多个参数

    通过len(arg)来判断传递参数的个数

    6、练习题示例

    package main

    import (
        "fmt"
    )

    //练习题一:写一个函数add,支持1个或多个int相加,并返回结果
    func add(a int,arg...int)int{
        var sum int
        //当只有一个参数时
        if len(arg)==0{
            sum = a
        }
        //当参数大于一个时
        if len(arg)>0{
            for i:=0;i<len(arg);i++{
                //注意这里但arg里面只有一个参数时,i是等于0即arg[0]
                if i == 0 {
                    sum = a + arg[0]
                }
                //当arg参数大于一个时
                if i >0 {
                    sum+=arg[i]
                }
            }
        }
        return sum
    }

    //练习题二:写一个函数concat,支持1个或多个string相拼接,并返回结果
    func concat(a string,arg...string)string{
        var str string
        if len(arg)==0{
            str = a
        }
        if len(arg)>0{
            for i:=0;i<len(arg);i++{
                if i == 0 {
                    str = a + arg[0]
                }
                if i >0 {
                    str+=arg[i]
                }
            }
        }
        return str
    }


    func main(){
        fmt.Println(add(-22,23,555))
        fmt.Println(concat("aaa","bbbbb","ccccccc"))
    }
     
    7、defer的特点和用途
    7.1、当函数返回时,执行defer语句。因此可以用来做资源清理
    7.2、多个defer语句,按先进后出的方式执行
    示例:
    func a(){
        fmt.Println("defer from a")
        i:=0
        defer fmt.Println(i)   //defer语句中的变量,在defer声明时就决定
        i++ 
    }
    func f(){
        fmt.Println("defer from f")
        for i:=0;i<5;i++{
            defer fmt.Println(i)
        }   
    }

    func main(){
        //练习三
        a()
        f()
    }
    打印的结果:
    7.3、defer语句中的变量,在defer声明时就决定了
    7.4、defer用途:关闭文件句柄,锁资源释放,数据库连接释放
     
    四、递归函数
    1、一个函数调用自己,就叫递归函数
    2、斐波那契数
    //斐波那契数列示例:
    func fb( n int)int{
        if n <=1{
            return 1
        }
        return fb(n-1)+fb(n-2)
    }
    func main(){
        for i:=0;i<10;i++{
            n := fb(i)
            fmt.Println(n)
        }
    }
    3、递归的设计原则
    3.1、一个大问题能够分解成相似的小问题
    3.2、定义好出口条件(即结束递归循环的条件)
     
    五、闭包
    一个函数和与其相关的引用环境的组合成的实体
    //示例一:
    func Adder() func(int)int{
        var x int
        return func(delta int)int{
            x +=delta
            return x
        }
    }
    //示例2:
    func makeSuffixFunc(suffix string) func(string)string{
        return func(name string)string{
            if !strings.HasSuffix(name ,suffix){
                return name + suffix
            }
            return name
        }
    }
    func main(){
        //练习五:闭包
        //示例1:
        // var f = Adder()
        // fmt.Println(f(1))
        // fmt.Println(f(10))
        // fmt.Println(f(100))
        //示例2:
        func1 := makeSuffixFunc(".jpg")
        func2 := makeSuffixFunc(".txt")
        fmt.Println(func1(func1("test")))
        fmt.Println(func2("test"))
    }
     
    六、数组和切片
    1.1、排序和查找操作
      排序操作主要都在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 必须有序
  • 相关阅读:
    POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)
    JAVA学习第四十一课 — 泛型的基本应用(一)
    (十九)组合模式详解
    计算机的组成 —— 主板
    计算机的组成 —— 主板
    查询电脑信息
    查询电脑信息
    计算机的组成 —— 显卡
    计算机的组成 —— 显卡
    云计算服务与基本术语、概念
  • 原文地址:https://www.cnblogs.com/willpower-chen/p/8057840.html
Copyright © 2020-2023  润新知