go函数闭包和类型引用与指针传递(33)

2023年 7月 15日 71.8k 0

闭包通常指变量的生命周期,闭包指的是返回一个函数的时候用来外面的闭包。通常一个函数调用完成后是需要销毁的,但在被内部作用域引用的情况下,是不能进行销毁的。

1.函数-闭包

  • 示例

一般而言,在调用一个匿名函数的时候,通常如下:

    add30 := func(n int) int {
        return n + 30
    }

匿名函数赋值给add30,返回值是传递的行参加30.

比如有多个,写多次

    add30 := func(n int) int {
        return n + 30
    }
    add20 := func(n int) int {
        return n + 20
    }
    add10 := func(n int) int {
        return n + 10
    }
    fmt.Println(add30(10))
    fmt.Println(add20(10))
    fmt.Println(add10(10))

运行

[root@linuxea.com /opt/Golang/work3]# go run add13.go 
40
30
20

现在,换种写法.

定义一个addBase,在匿名函数中定义一个int类型的base行参,作为基数,返回一个int类型的函数类型。如下:

addBase := func(base int) func(int) int {}

而后在其中返回.

首先返回值的类型是一个int的函数,那么就返回一个int类型的函数签名

addBase := func(base int) func(int) int {
    return func(n int) int{
        
    }
}

在返回的函数类型中,在return base + n

    addBase := func(base int) func(int) int {
        return func(n int) int{
            return base + n
        }
    }

return base + n中,base是匿名函数中的基数的变量,return base + n返回的就是匿名函数的基数base函数+返回值中的n

假如现在对addBase进行传参,比如传递一个实参,如8,addBase(8),这样就变成了, 8 +n,传递的8是base

赋值一个变量进行调用

    add1 := addBase(8)
    fmt.Printf("%Tn",add1)

add1现在也是一个函数类型。并且进行传值,而后打印

    fmt.Println(add1(8))

代码块

package main
import "fmt"

func main(){

    addBase := func(base int) func(int) int {
        return func(n int) int{
            return base + n
        }
    }
    
    add1 := addBase(8)
    fmt.Printf("%Tn",add1)
    fmt.Println(add1(8))
}

运行

[root@linuxea.com /opt/Golang/work3]# go run add13.go
func(int) int
16

或者这样

package main
import "fmt"

func main(){

    addBase := func(base int) func(int) int {
        return func(n int) int{
            return base + n
        }
    }
    fmt.Println(addBase(8)(8))
}    

运行

[root@linuxea.com /opt/Golang/work3]# go run add14.go
16

2.函数-值类型引用类型

对于值类型和引用类型的区分,主要看变量赋值给新的变量后,修改新变量后如果对旧变量有影响,就是引用类型,如果没有影响就是值类型

针对值类型和引用类型在赋值后新旧变量的地址并不相同,只是引用类型在底层共享数据结构(其中包含指针类型元素)

值类型:int(数值),bool(布尔),float(浮点数),array,指针,数组,结构体

引用类型:slice(切片),map(映射),接口等

  • 示例

创建两个切片分别是array和slice,而后赋值给sliceA和arrayA,并且修改sliceA和arrayA的索引0位置的A修改成Z,而后打印结果

package main
import "fmt"
func main(){
    array := [3]string{"A","B","C"}
    slice := []string{"A","B","C"}
    arrayA := array
    sliceA := slice
    arrayA[0] = "Z"
    sliceA[0] = "Z"
    fmt.Println(arrayA,array)
    fmt.Println(sliceA,slice)
}

运行

[root@linuxea.com /opt/Golang/work3]# go run add16.go
[Z B C] [A B C]
[Z B C] [Z B C]

对于值类型,要修改需要通过指针来操作

  • 示例

    定义age,分别通过赋值修改,和指针操作来修改值。如下:

package main
import "fmt"
func main(){
    age := 30
    ageA := age
    ageA = 31
    fmt.Println(ageA,age)

    pointer := &age
    *pointer = 31
    fmt.Println(*pointer,age)
}    

运行

[root@linuxea.com /opt/Golang/work3]# go run add17.go
31 30
31 31

最终指针修改会修改会影响到旧变量

3.函数-值传递指针传递

在go中只有值传递

  • 值传递

在go语言中参数传递默认为值传递(形参为实参变量的副本),对于引用类型数据因其底层共享数据结构,所以在函数内可对引用类型数据修改从而影响函数外的原变量信息。如下图

20190928.png

a赋值给b后,b是a复制的一份,而s1赋值给s2仍然共享底层数据

  • 指针传递

20190928-1.png

指针赋值给函数后,将会指到原来的地址,并修改内存中的数据。变量的值也就变了。行参和实参都是通过拷贝的,只不过值的数据是一样的,但是值的地址指向是不一样的。

  • 示例

值传递赋值的都是一个副本。引用类型数据因其底层共享数据结构。

创建一个changeIntchangeSlice函数,分别是int类型,和切片,而后分别赋值不同的类型元素通过参数传递给函数,而后打印结果

package main
import "fmt"
func changeInt(a int){
    a = 100
}
func changeSlice(s []int){
    s[0] = 100
}
func main(){
    num := 1
    changeInt(num)
    fmt.Println(num)
    
    nums := []int{1,2,3}
    changeSlice(nums)
    fmt.Println(nums)
}

运行

[root@linuxea.com /opt/Golang/work3]# go run add18.go
1
[100 2 3]

值类型传递并没有修改,说明changeInt修改没有影响,参数传递通过值类型传递给不同的地址。而引用类型传递后被修改,changeSlice修改完成,这些参数传递也是值类型传递,但是会指向同一一个内存区间。

如果此时要修改值类型,就需要指针操作

  • 指针传递

在原有的代码中添加一个changeIntByPoint函数

func changeIntByPoint(a *int){}

而后通过指针操作

*a = 100

如下:

package main
import "fmt"
func changeInt(a int){
    a = 100
}
func changeSlice(s []int){
    s[0] = 100
}
func changeIntByPoint(a *int){
    *a = 100
}
func main(){
    num := 1
    changeInt(num)
    fmt.Println(num)
    
    nums := []int{1,2,3}
    changeSlice(nums)
    fmt.Println(nums)
    
    changeIntByPoint(&num)
    fmt.Println(num)
}

运行

[root@linuxea.com /opt/Golang/work3]# go run add19.go 
1
[100 2 3]
100

现在值就变成了100

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论