• go基础部分学习笔记记录


    函数和方法的区别

    在Go语言中,函数和方法不太一样,有明确的概念区分。其他语言中,比如Java,一般来说函数就是方法,方法就是函数﹔但是在Go语言中,函数是指不属于任何结构体依类型的方法,也就是说函数是没有接收者的;而方法是有接收者的。

    方法

    func (t *T )add (a, b int) int {
    return a + b
    }
    
    • 1
    • 2
    • 3

    其中T是自定义奥型威者结构体。基础类型int等

    函数

    func add(a, b int) int {
    return a + b
    }
    
    • 1
    • 2
    • 3

    go方法值接收者和指针接收者的一个区别

    结论:
    如果方法的接收者是指针类型,无沦调用者是对象还是对象指针,修改的都是对象本身,会影响调用者;

    如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是对象的副本,不影响调用者;

    package main
    import "fmt"
    type Person struct {
    age int
    }
    //如果实现了接收者是指针类型的方法,会隐含地也实现了接收者是值类型的IncrAge1方法。
    //会修改age的值
    func (p *Person) IncrAge1( ) {
    p.age += 1
    }
    //如果实现了接收者是值类型的方法,会隐含地也实现了接收者是指针类型的IncrAge2方法。//不会修改age的值
    func (p Person) IncrAge2( ) {
    p.age += 1
    }
    //如果实现了接收者是值类型的方法,会隐含地也实现了接收者是指针类型的GetAge方法。
    func (p Person) GetAge( ) int i{
    return p.age
    }
    func main() {
    
    //p是值类型
    p := Person{age: 10}
    //值类型调用接收者是指针类型的方法
    p.IncrAge1()
    fmt.Println(p.GetAge( ))
    //值类型调用接收者是值类型的方法
    p.IncrAge2()
    fmt.Println(p.GetAge( ))
    
    
    
    //p2是指针类型
    p2:=&Person{age:20}
    //指针类型,调用者的接收者是指针类型的方法
    p2.IncrAge1()
    fmt.Println(p2.GetAge( ))
    //值类型调用接收者是值类型的方法
    p2.IncrAge2()
    fmt.Println(p2.GetAge( ))
    
    
    
    • 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

    通常我们使用指针类型作为方法的接收者的理由:

    1.使用指针类型能修改调用者的值。

    2.使用指针类型可以避免在每次调用方法时复制该值,在值的类型为大型结构体时,这样做会更加高效。


    go函数返回局部变量后是不是安全的吗?

    是安全的,但是会内存逃逸,分配在堆上面!!!


    go函数参数传递是值传递还是值传递

    Go语言中所有的传参都是值传递《传值),都是一个副本,一个拷贝。

    参数如果是非引用类型(int、 string、struet等这些),这样就在函致中就无法修改原内容数据;如果是引用类型 指针、map、slice、chan等这些),这样就可以修改原内容数据。

    是否可以修改原内容数据,和传值、传引用没有必然的关系。在C++中,传引用肯定是可以修改原内容数据的,在Go语言里,虽然只有传值,但是我们也可以修改原内容数据,因为参数是引用类型

    传递slice也是值传递,但是传过去的是引用类型,因为slice的底层是这样的
    在这里插入图片描述
    直接传过去虽然可以修改切片的值,但是没法修改len和cap,只有传slice的地址才可以修改len和cap

    map,chan本质也是一个指针,虽然是值传递,但是还是可以修改值

    引用类型和引用传递是2个概念,切记!!!


    defer的原理

    定义:
    defer能够让我们推迟执行某些函数调用,推迟到当前函数返回前才实际执行。defer与panic和recover结合,形成了Go语言风格的异常与捕获机制。

    使用场景:
    defer语句经常被用于处理成对的操作,如文件句柄关闭、连接关闭、释放锁

    优点:
    方便开发者使用

    缺点:

    有性能损耗

    实现原理:

    Go1.14中编译器会将deleri函数直接插入到函数的尾部,无需链表和栈上参数拷贝,性能大幅提升。把deler函数在当前函致内展开并直接调用,这种方式被称为open coded defer

    注意:


    2.panic后的defer函数不会被执行(遇到panic如果没有捕获到错误,函数会立即停止)

    在这里插入图片描述

    3. panic没有被recover时,抛出的panic到当前goroutine最上层函数时,最上层程序直接异常终止

    package main
    import "fmt"
    func F() {
    defer func(){
    fmt.Println(""b")
    }()
    panic("a"")
    }
    //子函数抛出的panic没有recover时,上层函数时,程序直接异常终止
    func main(){
    defer func(){
    fmt.Println(""c"")
    }()
    F()
    fmt.Println("继续执行")
    }
    //b
    //c
    //panic: a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4. panic有被recover时,当前goroutine最上层函数正常执行

    package main
    import "fmt"
    func F() {
    defer func() {
    if err := recover() ; err != nil {
    fmt.Println("捕获异常: ",err)
    }
    fmt.Println(""b)
    }()
    panic("a")
    }
    func main(){
    defer func(){
    fmt.Println("c")
    }()
    F()
    fmt.Println("继续执行")
    }
    //捕获异常: a 
    // b
    //继续执行
    // c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    make和nwe函数

    首先纠正下make和new是内置函数,不是关键字

    变量初始化,一般包括2步,变量声明+变量内存分配,var关键字就是用来声明变量的, new和make函数主要是用来分配内存的

    var声明值类型的变量时,系统会默认为他分配内存空间,并赋该类型的零值。比如布尔、数字、字符串、结构体。如果指针类型或者引用类型的变量,系统不会为它分配内存,默认就是ni1。此时如果你想直接使用,那么系统会抛异常,必须进行内存分配后,才能使用。

    new和 make两个内置函数,主要用来分配内存空间,有了内存,变量就能使用了,主要有以下2点区别:

    1.使用场景区别:

    make只能用来分配及初始化类型为slice、map、chan的数据。

    new可以分配任意类型的数据,并且置零。

    2.返回值区别:

    make函数原型如下,返回的是slice、map、chan类型本身

    这3种类型是引用类型,就没有必要返回他们的指针

    func make(t Type,size ...Integer Type)Type
    
    • 1

    new函数原型如下,返回一个指向该类型内存地址的指针

    func new(Type)*Type
    
    • 1
  • 相关阅读:
    Page分页records有数据,但是total=0,解决办法
    基于JAVA-游戏账号交易平台-演示录像-计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    微服务项目:尚融宝(37)(核心业务流程:用户绑定(2))
    spring整合SpringCache
    Java之UDP,TCP的详细解析
    tensor.eq() tensor.item() tensor.argmax()
    牛客刷题<21>三段式状态机
    数据查询必备技能SQL调优:Mysql什么情况下不走索引
    Shell基础介绍与Shell编程基础
    《大数据》第七章 聚类 K-means算法 BFR算法 CURE算法
  • 原文地址:https://blog.csdn.net/qq_52563729/article/details/126069930