在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
在整理函数之前先整理一下关于指针 指针普通类型变量存的就是值,也叫值类型。指针类型存的是地址,即指针的值是一个变量的地址。 获取变量的地址,用&,例如:var a int 获取a的地址:&a,&a(a的地址)这个表达式获取一个指向整形变量的指针,它的类型是整形指针(*int),如果值叫做p,我们说p指向x,或者p包含x的地址,p指向的变量写成 指针类型的零值是nil 通过下面小例子进行理解指针: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func test() { 8 x := 1 9 // &x 获取的是变量x的地址,并赋值给p,这个时候p就是一个指针 10 p := &x 11 // p是指针,所以*p获取的就是变量的值,指针指向的是变量x的值,即*p为1 12 fmt.Println(*p) 13 // 这里*p 进行赋值,也就是更改了变量x的值,即实现不知道变量的名字更改变量的值 14 *p = 2 15 fmt.Println(x) 16 } 17 18 func main() { 19 test() 20 } 再看一个关于通过一个函数来修改变量值的问题: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func modify(num int) { 8 num = 100 9 } 10 11 func main() { 12 a := 10 13 modify(a) 14 fmt.Println(a) 15 } 这个例子是修改变量的值,但是最后打印变量a的值是还是10,所以这里就需要知道,当通过定义的函数modify来修改变量的值时,传入变量a其实会进行一次拷贝,传入的其实是a变量的一个副本,所以当通过 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func modify(num *int) { 8 *num = 100 9 } 10 11 func main() { 12 a := 10 13 modify(&a) 14 fmt.Println(a) 15 } 这里定义modify函数的时候参数设置的是一个指针,所以我们传入参数时,传入的是&a即变量a的地址,而这个地址指向的值是10,虽然这次传入的参数也是进行了传入的指针进行了一次拷贝,但是即使是拷贝了副本指向的值还是10,所以当我们通过指针*num修改值的时候其实就是在修改变量a的值。 内置函数len: 用于求长度,比如string、array、slice、map、channel 下面重点整理new和make new函数func new(Type) *Type new函数也是创建变量的一种方式。表达式new(T)创建一个未命名的T类型变量,初始化T类型的零值,并返回其地址(地址类型为*T) 通过下面例子进行理解: 1 package main 2 3 import "fmt" 4 5 func newFunc() { 6 p := new(int) 7 fmt.Println(p) //打印是地址 8 fmt.Println(*p) //int类型的零值为0这里打印0 9 *p = 2 10 fmt.Println(*p) //*p已经为其地址指向了一个变量2,所以这里打印为2 11 } 12 13 func main() { 14 newFunc() 15 } 这里我们要知道new创建的变量和取其地址的普通局部变量没有什么不同,只是语法上的便利 1 func newInt() *int { 2 return new(int) 3 } 4 5 func newInt2() *int { 6 var res int 7 return &res 8 } 如果我们定义一个指针是不能直接给这个指针赋值的,而是需要先给这个指针分配内存,然后才能赋值 正确的做法是我们需要先通过new初始化,正确代码如下: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func test(){ 8 var p *int 9 p = new(int) 10 *p = 10 11 fmt.Println(*p) 12 } 13 14 func main(){ 15 test() 16 } make函数func make(Type, size IntegerType) Type 其实在上一篇整理切片slice的时候就用到了make如: 这里提前说一下通过make初始化map的时候,根据size大小来初始化分配内存,不过分配后的map长度为0,如果size被忽略了,会在初始化分配内存的时候分配一个小的内存 关于new和make的一个小结: 函数函数的声明语法:func 函数名 (参数 表) [(返回值 表)] {} 常见的几种声明函数的方法: } 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){ } golang函数的特点:
演示一些函数的例子: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func add(a, b int) int { 8 return a + b 9 } 10 11 func main() { 12 c := add //这里把函数名赋值给变量c 13 fmt.Printf("%p %T", c, add) 14 sum := c(10, 20) //调用c其实就是在调用add 15 fmt.Println(sum) 16 17 } golang函数还有一个用法例子: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 type addFunc func(int, int) int 8 9 func add(a, b int) int { 10 return a + b 11 } 12 13 func operator(op addFunc, a int, b int) int { 14 return op(a, b) 15 } 16 17 func main() { 18 c := add 19 sum := operator(c, 100, 200) 20 fmt.Println(sum) 21 } 变量作用域 在函数外面的变量是全局变量 关于函数的可变参数 变长函数被调用的时候可以有可变的参数个数 } } } 关于函数参数的传递 不管是值类型还是引用传递,传递给函数的都是变量的副本 延迟函数defer的调用 语法上,一个defer语句就是一个普通的函数或者方法调用,在调用之前加上关键字defer。函数和参数表达式会在语句执行时求值,但是无论是正常情况还是执行return语句或者函数执行完毕,以及不正常情况下,如程序发生宕机,实际的调用推迟到包含defer语句的函数结束后才执行,defer语句没有限制使用次数。 defer用途:
先通过一个小例子理解defer: 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 8 func testDefer(){ 9 a := 100 10 fmt.Printf("before defer:a=%d\n",a) 11 defer fmt.Println(a) 12 a = 200 13 fmt.Printf("after defer:a=%d\n",a) 14 15 } 16 17 func main(){ 18 testDefer() 19 } 这里我们可以这样理解当我们执行defer语句的时a=100,这个时候压入到栈中,等程序最后结束的时候才会调用defer语句,所以打印的顺序是最后才打印一个数字100 defer语句经常使用成对的操作,比如打开和关闭,连接和断开,加锁和解锁 下面拿关闭一个打开文件操作为例子,当我们通过os.Open()打开一个文件的时候可以在后面添加defer f.Close() 这样在函数结束时就可以帮我们自动关闭一个打开的文件 Map类型key-value的数据结构,又叫字典 声明 例子: 注意:声明是不会分配内存的需要make初始化 初始化的两种方式: 插入和更新 查找 遍历 删除 这个操作是安全的,及时这个元素不存在也不会报错,如果一个查找失败将返回value类型对应的零值 长度 map是引用类型
注意:map中的元素并不是一个变量,所以我们不能对map的元素进行取址操作 |
请发表评论