指针
- 区别于C/C++,Go语言中的指针不能进行偏移和运算,是安全指针。
- 要搞明白Go中的指针需先知道3个概念:指针地址,指针类型和指针取值
1.Go语言指针:
-
Go语言中函数传参都是值拷贝,当我们想要修改某个变量时候,我们可以创建一个指向该变量地址的指针变量,传递数据使用指针,而无需拷贝数据,类型指针不能进行偏移和运算,Go语言中的指针操作非常简单,只要记住两个符号:
-
指针地址和指针类型:
- 每个变量在运行时都有一个地址,这个地址代表变量在内存中为自己,Go语言中使用
& 字符放在变量前面对变量进行“取地址”操作,Go语言中的值类型(int,float,bool,string,array,struct)都有对应的指针类型,如:*int ,*int64 ,*string 等。
-
取变量指针的语法如下:
ptr := &v
其中:
- v 代表被取地址变量 类型为T
- ptr 用于接收地址的变量,ptr的类型就为*T,称为T的指针类型,*代表指针。
-
指针简单示例:
package main
import "fmt"
//指针
func main() {
a := 10
b := &a //*int 得到a的变量内存地址
fmt.Printf("%v %p\n", a, &a) //10值 0x11048058内存地址
fmt.Println(b) //0x11048058内存地址
//变量b是一个int类型的指针(*int),它存储的是变量a的内存地址
c := *b//根据内存地址去取值
fmt.Println(c)//10
}
-
总结:
- 取地址操作符
& 和取值操作符* 是一对互补操作符 & 去取地址,* 根据地址取出地址指向的值,变量,指针地址,指针变量,取地址/取值的相互关系和特性如下:
- 对变量进行取地址
& 操作,可以获得这个变量的指针变量
- 指针变量的值是指针的地址。
- 对指针变量进行取值
* 操作,可以获得指针变量指向的原变量的值。
package main
import "fmt"
func modify1(x int) {
x = 100
}
func modify2(y *int) {
*y = 100
}
func main() {
a := 1
modify1(a)//传入a的值
fmt.Println(a)//a的值没有变化
modify2(&a)//传入a内存地址
fmt.Println(a)//a的值发生变化
}
//1
//100
-
数值交换
func swap(a, b *int) {
*a, *b = *b, *a
}
func main() {
a, b := 3, 4
swap(&a, &b)
fmt.Println(a, b)//4,3
}
-
空指针
- 当一个指针别定义后没有分配到任何变量时,它的值为nil
- 空指针的判断
package main
import "fmt"
func main() {
var p *string
fmt.Println(p)
fmt.Printf("p的值是%s.\n",p)
if p != nil {
fmt.Println("不是空")
} else {
fmt.Println("空值")
}
// <nil>
// p的值是%!s(*string=<nil>).
// 空值
}
2.new与make
- new用来分配内存,但与其他语言中的同名函数不同,它不会初始化内存,只会将内存置零。
- make(T)会返回一个指针,该指针指向新分配的,类型为T的零值。适用于创建结构体。
- make()的目的不同于new() ,它只能创建slice,map,channel,并返回类型为T(非指针)的已初始化(非零值)的值。
new:
-
是一个内置的函数,的函数签名如下
func new(Type) *Type
-
其中:
- Type表示类型,new函数只接收一个参数,这个参数是一个类型。
- Type表示类型指针,new函数返回一个指向该类型内存地址的指针。
-
new函数不太常用,使用new函数得到的是一个类型指针,并且该指针对应的值为该类型零值,举个例子:
a := new(int)
fmt.Println(a) //0x1104a058
fmt.Printf("%T\n", a)//*int
- Type表示类型,new函数只接受一个参数,这个参数是一个类型。
- *Type表示类型指针:new函数返回一个指向该类型内存地址的指针。
package main
import "fmt"
/*
func main() {
var a *int//a是一个空指针,
fmt.Println(*a)
var b map[string]int//需要make操作,让其在内存地址有一定空间
b["xjk"] = 100
fmt.Println(b)
}
//以上代码会报错
*/
func main() {
var a *int//a是一个空指针,声明一个指针变量,但没有初始化
a = new(int)//对指针做一个初始化,分配内存空间
*a = 10//再给它赋值
fmt.Println(*a)
var b map[string]int//需要make操作,让其在内存地址有一定空间
b = make(map[string]int,10)
b["xjk"] = 100
fmt.Println(b)// 10
}
make:
-
make也是用于内存分配的,区别于new,它只用于slice、map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。make函数的函数签名如下:
func make(t Type,size ...InterType)Type
-
make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。
var b map[string]int
b = make(map[string]int, 10)
b["rmb"] = 100
fmt.Println(b) //map[rmb:100]
-
new和make的区别:
- 二者都是用来做内存分配的
- make只用于slice,map一级channel的初始化,返回还是这3个引用类型本身
- 而new用于类型的内存分配,并且内存对应的值为类型的零值,返回的是指向类型的指针
-
练习:程序定义一个int变量num的地址并打印,将num的地址赋给指针ptr,并通过ptr去修改num的值
package main
import "fmt"
func main() {
var a int
fmt.Println(&a)
var p *int
p = &a
*p = 20
fmt.Println(a)
// 0x1104a058
// 20
}
|
请发表评论