您的位置:首页 > 新闻 > 会展 > 【golang学习之旅】复杂数据类型——指针 函数

【golang学习之旅】复杂数据类型——指针 函数

2025/3/10 23:11:31 来源:https://blog.csdn.net/m0_60511809/article/details/139970929  浏览:    关键词:【golang学习之旅】复杂数据类型——指针 函数

系列文章

【golang学习之旅】使用VScode安装配置Go开发环境
【golang学习之旅】报错:a declared but not used
【golang学习之旅】Go 的基本数据类型
【golang学习之旅】深入理解字符串string数据类型
【golang学习之旅】go mod tidy
【golang学习之旅】记录一次 panic case : reflect: reflect.Value.SetInt using unaddressable value
【golang学习之旅】记录一次 error case : full error output: cc1: error: unrecognized command line option
【golang学习之旅】Go程序快速开始 & Go程序开发的基本注意事项
【golang学习之旅】Go语言常用转义字符
【golang学习之旅】Go中的变量(1)
【golang学习之旅】Go中的变量——基本数据类型(1)
【golang学习之旅】Go中的变量——基本数据类型(2)


  • 系列文章
  • 指针
  • 函数
    • 基本语法
    • 函数注意事项和细节讨论
    • init()函数
    • 匿名函数
    • 闭包


指针

基本数据类型,变量存的就是值,所以也叫值类型。

指针类型,指针变量存的是一个地址,这个地址所指向的空间存的才是值

package mainimport "fmt"func main() {var a int = 10fmt.Println("a 的地址:", &a)// ptr是一个指针变量,它的类型是*int,它指向int类型的变量avar ptr *int = &afmt.Printf("ptr的值: %v, ptr 的地址: %v\n", ptr, &ptr)fmt.Println("ptr指向的值:", *ptr)// 修改ptr指向的值*ptr = 20fmt.Println("修改后a的值:", a)
}输出:
a 的地址: 0xc00000a0b8
ptr的值: 0xc00000a0b8, ptr 的地址: 0xc00005a028
ptr指向的值: 10
修改后a的值: 20
  • 获取变量的地址使用&符号

  • 获取指针类型所指向的值,使用*

  • 可以通过指针修改所指向变量的值

练习:

在这里插入图片描述

值类型有:基本数据类型(int系列,float系列,bool,string)、复杂数据类型中的复合数据类型(数组和结构体)

引用类型有:非值类型就是引用类型


函数

基本语法

func 函数名(形参列表) (返回值列表){执行语句...
}
  • 函数声明包含一个函数名参数列表返回值列表函数体。如果函数没有返回值,则返回列表可以省略
  • 函数可以没有参数或接受多个参数
  • 函数可以返回任意数量的返回值。有返回值的函数,必须有明确的终止语句,否则会引发编译错误

在这里插入图片描述

Go中的每一个文件都属于一个包,也就是说Go是以包的形式来管理文件和项目目录结构的。

包的作用

  • 区分相同名字的函数、变量等标识符。不同包的文件中允许重名的标识符
  • 当程序文件很多时,可以很好的管理项目。比如module包、dao包、service包等等
  • 控制函数、变量等访问范围

包的注意事项

  1. 文件的包名通常和文件所在的文件夹名一致,一般为小写字母。

    在这里插入图片描述

  2. 当一个文件要使用其他包的函数或变量时,需先引入对应的包

    • 引入方式1:import “包名/包路径”

    • 引入方式2:

      import ("包名""包名"
      )
      

      在这里插入图片描述

  3. package指令在文件第一行,然后是import指令。接下来才是变量、函数声明等等

  4. 在访问其他包函数、变量时,其语法是包名.函数名

    在这里插入图片描述

  5. 如果包名较长,Go支持给包取别名。取别名后,原来的包名就不能使用了

    在这里插入图片描述

  6. 在同一个包下,不能有相同的函数名,否则报重复定义

函数注意事项和细节讨论

  1. 函数的形参列表可以是多个,返回值也可以是多个

  2. 函数的命名遵循标识符命名规范,首字母不能是数字。首字母是大写则该函数可以被其他包访问到,如果是小写,只能被本包文件使用

  3. 基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改值不会影响原值

package mainimport ("fmt"
)func test(name string) {name = "test"fmt.Println("test() ", name)
}
func main() {name := "main"test(name)fmt.Println("main() ", name)
}输出:
test()  test
main()  main
  1. 如果希望函数内的变量能够修改函数外的变量(指的是以值传递的方式的基本数据类型),可以传入变量的地址,函数内以指针的方式操作变量(从效果上类似引用数据类型的使用)

    package mainimport ("fmt"
    )func test(name *string) {*name = "test"fmt.Println("test() ", *name)
    }
    func main() {name := "main"test(&name)fmt.Println("main() ", name)
    }输出:
    test()  test
    main()  test
    
  2. 在Go中,函数本身也是一种数据类型,可以赋值给一个变量,通过该变量可以实现对函数的调用

    package mainimport ("fmt"
    )func getSum(n1, n2 int) int {return n1 + n2
    }
    func main() {a := getSumfmt.Printf("a 的类型 %T\n", a)res := a(1, 2) // 等价于 res := getSum(1, 2)fmt.Printf("res 的值 %d\n", res)
    }输出:
    a 的类型 func(int, int) int
    res 的值 3
    
  3. 为了简化数据定义,Go支持自定义数据类型。相当于一个别名

    比如:type myInt int //这时myInt就等价于int来使用了

  4. Go函数支持对返回值命名

    在这里插入图片描述

  5. 使用 _ 标识符时表示忽略该值,可以用作占位符

  6. Go支持可变参数。这里的可变参数实际上是slice切片,通过 args[index]的方式来访问各个值

    package mainimport ("fmt"
    )func getSum(num ...int) int {sum := 0for i := 0; i < len(num); i++ {sum += num[i]}return sum
    }
    func main() {sum := getSum(1, 2, 3, 4)fmt.Println(sum)
    }输出:
    10
    

init()函数

每一个源文件都可以包含一个init()函数,该函数会在main函数执行前,被Go运行框架调用。

package mainimport ("fmt"
)func init() {fmt.Println("init()...")
}func main() {fmt.Println("main()...")
}输出:
init()...
main()...
  1. 如果一个文件同时包含全局变量定义、init函数和main函数,那么执行的顺序是 : 全局变量定义->init函数->main函数
  2. init()函数最主要的作用是完成一些初始化的工作

匿名函数

使用方式:

  1. 在定义匿名函数时就直接调用
  2. 将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数
package mainimport ("fmt"
)func main() {// 求两数之和// 匿名函数方式1res1 := func(n1, n2 int) int {return n1 + n2}(10, 20)fmt.Println("匿名函数方式1...res1 = ", res1)// 匿名函数方式2func1 := func(n1, n2 int) int {return n1 + n2}res2 := func1(10, 20)fmt.Println("匿名函数方式2...res2 = ", res2)
}输出:
匿名函数方式1...res1 =  30
匿名函数方式2...res2 =  30

闭包

闭包就是第一个函数和与其相关的引用环境组合的一个整体(实体)。

现在开始通过例子来说明闭包:

func incr() func() int {var x intreturn func() int {x++return x}
}

调用这个函数会返回一个函数变量。

i := incr():通过把这个函数变量赋值给 ii 就成为了一个闭包

所以 i 保存着对 x 的引用,可以想象 i 中有着一个指针指向 xi 中有 x 的地址

由于 i 有着指向 x 的指针,所以可以修改 x,且保持着状态:

println(i()) // 1
println(i()) // 2
println(i()) // 3

也就是说,x 逃逸了,它的生命周期没有随着它的作用域结束而结束

但是这段代码却不会递增:

println(incr()()) // 1
println(incr()()) // 1
println(incr()()) // 1

这是因为这里调用了三次 incr(),返回了三个闭包,这三个闭包引用着三个不同的 x,它们的状态是各自独立的。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com