认识指针地址和指针类型:
Go语言中使用“&”操作符放在变量前面对变量进行“取地址”操作
格式如下:
ptr := &v //v的类型为T
其中v代表被取地址的变量,被取地址的v使用ptr变量进行接收,ptr的类型就为“*T”,称做T的指针类型。“*”代表指针。
代码如下:
package main
import(
"fmt"
)
func main(){
var cat int=1
var str string ="banana"
fmt.Printf("%p %p\n", &cat, &str)
}
结果如下:
0xc000018060 0xc000010230
使用fmt.Printf的动词“%p”输出cat和str变量取地址后的指针值,指针值带有“0x”的十六进制前缀。
从指针获取指针指向的值:
代码如下:
package main
import(
"fmt"
)
func main(){
//准备一个字符串类型
var house ="Malibu Point 10880,90265"
//字符串取地址,ptr类型为*string
ptr:=&house
//打印ptr的类型
fmt.Printf("ptr type: %T\n",ptr)
//打印ptr的指针类型
fmt.Printf("address: %p\n",ptr)
//对指针进行取值操作
value:=*ptr
//取值后的类型
fmt.Printf("value type: %T\n",value)
//指针取值后就是指向变量的值。
fmt.Printf("value: %s\n",value)
}
结果如下:
ptr type: *string
address: 0xc000010230
value type: string
value: Malibu Point 10880,90265
取地址操作符“&”和取值操作符“*”是一对互补操作符,“&”取出地址,“*”根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
●对变量进行取地址(&)操作,可以获得这个变量的指针变量。
●指针变量的值是指针地址。
●对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
使用指针修改值:
代码如下:
package main
import(
"fmt"
)
//交换函数
func swap(a,b *int){
//取a指针的值,赋给临时变量t
t:=*a
//取b指针的值,赋给a指针指向的变量
*a=*b
//将a指针的值赋给b指针指向的变量
*b=t
}
func main(){
//准备两个变量,赋值1和2
x,y:=1,2
//交换变量值
swap(&x,&y)
//输出变量值
fmt.Println(x,y)
}
运行结果如下:
2 1
代码如下:
package main
import(
"fmt"
)
func swap(a,b *int){
b,a=a,b
}
func main(){
x,y:=1,2
swap(&x,&y)
fmt.Println(x,y)
}
运行结果如下:
1 2
使用指针变量获取命令行的输入信息:(不能理解,没看懂)
代码如下:
package main
import(
"fmt"
"flag"
)
var mode = flag.String("mode","","process mode")
func main(){
flag.Parse()
fmt.Println(*mode)
}
在终端输入:
go run main.go --mode=fast
结果如下:
fast
创建指针的另一个方法----new()函数
格式如下:
new (类型)
new函数可以创建一个对应类型的指针,创建过程会分配内存。被创建的指针指向的值为默认值。
指针变量都是一个内存位置,每个内存位置都有其定义的地址,可以使&运算符来访问它,这个运算符表示内存中的地址。
打印变量a的地址,代码如下:
package main
import (
"fmt"
)
func main() {
a := 10
fmt.Printf("%x\n", &a)
}
运行结果如下:
c000018070
指针是一个变量,其值是另一个变量的地址,即存储器位置的直接地址。
指针变量声明的一般形式是:
var name *type
使用指针基本上是三个步骤:定义一个指针变量,将一个变量的地址赋值给一个指针,最后访问指针变量中可用地址的值。
代码如下:
package main
import (
"fmt"
)
func main() {
a := 20
ap := &a
fmt.Printf("a的地址:%x\n", &a)
fmt.Printf("ap的地址:%x\n", ap)
fmt.Printf("*ap的地址:%x\n", *ap)
}
运行结果如下:
a的地址:c000018070
ap的地址:c000018070
*ap的地址:14
Go语言指针不支持指针运算,也不支持->运算符。
1、nil指针
Go语言编译器为指针变量分配一个nil值,以防指针没有确切的地址分配,这是在变量声明的时候完成的。
代码如下:
package main
import (
"fmt"
)
func main() {
var ptr *int
fmt.Printf("ptr的值是:%x\n", ptr)
}
运行结果如下:
ptr的值是:0
要检查是否为nil指针,可以使用if语句,如下所示:
if(ptr!=nil)
if(ptr==nil)
2、指针的指针
指针的指针声明方式,代码如下:
package main
import (
"fmt"
)
func main() {
var a *int
aP := &a
fmt.Printf("a-->nil: %x\n", a)
fmt.Printf("aP-->a: %x\n", aP)
fmt.Printf("aP-->a-->nil(指针aP指向的指针a的内存地址): %x\n", *aP)
fmt.Printf("&aP-->aP(表示aP在内存中的地址): %x\n", &aP)
}
运行结果如下:
a-->nil: 0
aP-->a: c00012c018
aP-->a-->nil(指针aP指向的指针a的内存地址): 0
&aP-->aP(表示aP在内存中的地址): c00012c020
代码如下:
package main
import (
"fmt"
)
func main() {
a := 10
aP := &a
aPP := &aP
fmt.Printf("a: %d\n", a)
fmt.Printf("aP: %x\n", aP)
fmt.Printf("*aP: %d\n", *aP)
fmt.Printf("aPP: %x\n", aPP)
fmt.Printf("*aPP: %x\n", *aPP)
fmt.Printf("**aPP: %d\n", **aPP)
}
运行结果如下:
a: 10
aP: c000018070
*aP: 10
aPP: c00000e028
*aPP: c000018070
**aPP: 10
3、指针数组
代码如下:
package main
import (
"fmt"
)
func main() {
const MAX int = 3
a := []int{10, 100, 200}
var ptr [MAX]*int
for i := 0; i < MAX; i++ {
ptr[i] = &a[i]
fmt.Printf("a[%d]的地址:%d\n", i, ptr[i])
}
for i := 0; i < MAX; i++ {
fmt.Printf("a[%d]的地址:%d\n", i, *ptr[i])
}
}
运行结果如下:
a[0]的地址:824633843904
a[1]的地址:824633843912
a[2]的地址:824633843920
a[0]的地址:10
a[1]的地址:100
a[2]的地址:200
4、传递给函数
Go语言允许传递指针到函数中,只需将函数的参数声明为指针类型。
代码如下:
package main
import (
"fmt"
)
func main() {
a := 100
b := 200
fmt.Printf("交换之前a的值为:%d\n", a)
fmt.Printf("交换之前b的值为:%d\n", b)
swap(&a, &b)
fmt.Printf("交换之后a的值为:%d\n", a)
fmt.Printf("交换之后b的值为:%d\n", b)
}
func swap(x *int, y *int) {
var temp int
temp = *x
*x = *y
*y = temp
}
运行结果如下:
交换之前a的值为:100
交换之前b的值为:200
交换之后a的值为:200
交换之后b的值为:100
new()和make()的区别
new()用于值类型的内存分配,并且轩为零值。
make()只用于切片、字典以及通道这三种引用数据类型的内存分配和初始化。
new(T)分配类型T的零值并返回其地址,也就是指向类型T的指针。
make(T)返回类型T的值(不是*T)。
代码如下:
package main
import (
"log"
"runtime"
"time"
)
type Person struct {
Name string
Age int
}
func (p *Person) Close() {
p.Name = "NewName"
log.Println(p)
log.Println("Close")
}
func (p *Person) NewOpen() {
log.Println("Init")
runtime.SetFinalizer(p, (*Person).Close)
}
func Tt(p *Person) {
p.Name = "NewName"
log.Println(p)
log.Println("Tt")
}
// 查看内存情况
func Mem(m *runtime.MemStats) {
runtime.ReadMemStats(m)
log.Printf("%d Kb\n", m.Alloc/1024)
}
func main() {
var m runtime.MemStats
Mem(&m)
var p *Person = &Person{Name: "lee", Age: 4}
p.NewOpen()
log.Println("Gc完成第一次")
log.Println("p:", p)
runtime.GC()
time.Sleep(time.Second * 5)
Mem(&m)
var p1 *Person = &Person{Name: "Goo", Age: 9}
runtime.SetFinalizer(p1, Tt)
log.Println("Gc完成第二次")
time.Sleep(time.Second * 2)
runtime.GC()
time.Sleep(time.Second * 2)
Mem(&m)
}
运行结果如下:
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go> go run main.go
2022/08/19 14:10:15 108 Kb
2022/08/19 14:10:15 Init
2022/08/19 14:10:15 Gc完成第一次
2022/08/19 14:10:15 p: &{lee 4}
2022/08/19 14:10:15 &{NewName 4}
2022/08/19 14:10:15 Close
2022/08/19 14:10:20 99 Kb
2022/08/19 14:10:20 Gc完成第二次
2022/08/19 14:10:23 &{NewName 9}
2022/08/19 14:10:23 Tt
2022/08/19 14:10:25 99 Kb
PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\Go>