Go语言之流指针类型,new函数

计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用 4 个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。

我们将内存中字节的编号称为地址(Address)或指针(Pointer)。地址从 0 开始依次增加,对于 32 位环境,程序能够使用的内存为 4GB,最小的地址为 0,最大的地址为 0XFFFFFFFF。

数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量。
Go语言中使用对于指针存在两种操作: 取址和取值。

Go语言之流指针类型,new函数_第1张图片

var x = 100
// 取址符:&  取值符:*
fmt.Println("x的地址:", &x)
// 将地址值赋值给的变量称为指针变量
var p *int
p = &x
fmt.Println("p的值:", p)
fmt.Println("p地址对应的值", *p)

Go语言之流指针类型,new函数_第2张图片
关于地址的格式化打印

var x = 10
fmt.Printf("%p\n", &x)
x = 100
fmt.Printf("%p\n", &x)
fmt.Println(*&x)

关于指针的应用:

// 当使用等号将一个变量的值赋给另一个变量时,如 x = y ,实际上是在内存中将 i 的值进行了拷贝
var x = 10
var y = x
var z = &x
x = 20
fmt.Println(y)
fmt.Println(*z)
*z = 30
fmt.Println(x)

练习

var x = 10
var y = &x
var z = *y
x = 20
fmt.Println(x)
fmt.Println(*y)
fmt.Println(z) 

//=====================================

var a = 100
var b = &a
var c = &b
**c = 200
fmt.Println(a)

Go语言的指针类型变量即拥有指针高效访问的特点,又不会发生指针偏移和运算,从而避免了非法修改关键性数据的问题。

new函数

new 和 make 是 Go 语言中用于内存分配的原语。简单来说,new 只分配内存,make 用于初始化 slice、map 和 channel。
之前我们学习的基本数据类型声明之后是有一个默认零值的,但是指针类型呢?

在Go语言中,new函数和make函数都用于创建新的对象,但是它们有不同的用途和适用范围。

  1. new函数:new函数用于创建值类型的对象,并返回一个指向该对象的指针。它的语法是new(T),其中T表示类型。new函数会分配内存,并将分配的内存初始化为零值,然后返回指向该内存的指针。这个指针可以直接访问和操作对象的字段。例如:
p := new(int) // 创建一个新的int类型对象,并返回指向该对象的指针
fmt.Println(*p) // 输出0,因为内存被初始化为零值
*p = 42 // 修改对象的值
fmt.Println(*p) // 输出42
  1. make函数:make函数用于创建引用类型的对象,如切片、映射和通道,并返回一个已初始化的对象。它的语法是make(T, args),其中T表示类型,args表示用于初始化的参数。make函数会分配内存,并初始化对象的相关字段,返回一个可以直接使用的对象。例如:
s := make([]int, 5) // 创建一个长度为5的切片,并初始化为零值
fmt.Println(s) // 输出[0 0 0 0 0]
s[0] = 1 // 修改切片的值
fmt.Println(s) // 输出[1 0 0 0 0]

总结:

  • new函数用于创建值类型的对象,并返回一个指向该对象的指针。
  • make函数用于创建引用类型的对象,并返回一个已初始化的对象。
  • new函数只分配内存,不进行初始化,返回的是指向零值的指针。
  • make函数分配内存并进行初始化,返回的是已初始化的对象。

需要根据具体的需求和类型选择使用new函数还是make函数。

var p *int
// fmt.Println(p)  // 
// fmt.Println(*p) // 报错,并没有开辟空间地址
*p = 10. // 报错

我们可以看到初始化⼀个指针变量,其值为nil,nil的值是不能直接赋值的。通过内建的new函数返回⼀个指向新分配的类型为int的指针,指针值为0xc00004c088,这个指针指向的内容的值为零(zero value)。

 var p *int = new(int)
    fmt.Println(p)  // 0x14000122008
    fmt.Println(*p) // 0
    *p = 10
    fmt.Println(*p) // 10

make返回的还是引⽤类型本⾝;⽽new返回的是指向类型的指针。后面再详细介绍

func1_指针1() {
	//&变量,获取变量地址
	var x = 10
	fmt.Printf("赋值之前x的对应地址:%p\n", &x)
	x = 100
	fmt.Printf("赋值之后x的对应地址:%p\n", &x)
	fmt.Println(x)
}
func2_指针2() {
	//取址
	//赋值
	//取值

	//(1) 或取地址:&变量
	var x = 10 //x称为整型变量
	//(2) 地址赋值:指针类型
	var p *int //p是一个整型指针类型
	p = &x     // var p = &x
	fmt.Println(p)
	//(3)取值操作,*指针变量
	fmt.Println(*p, reflect.TypeOf(*p))
}
func3_接收指针类型() {
	//指针类型存储地址值
	//地址本身也有一个类型
	var x = 10
	fmt.Println(&x)
	//p就是指针变量
	var p *int
	p = &x
	fmt.Println(p)
	fmt.Println(*p, reflect.TypeOf(*p))
	*p = 100
	fmt.Println(*p)
	fmt.Println(x)
}
func4_思考题() {
	var a = 1
	var b = a
	b = 100
	fmt.Println(a, b)
	//如何指向同一块儿空间
}
func5_指针案例3() {
	var a = 100
	fmt.Println(reflect.TypeOf(a))
	var b = &a
	fmt.Println(reflect.TypeOf(b))
	var c = &b
	fmt.Println(reflect.TypeOf(c))
	**c = 200
	fmt.Println(a)
}
func6_指针案例4() {
	p1 := 1   //p1类型
	p2 := &p1 //*int类型
	*p2++
	fmt.Println(p1)
	fmt.Println(*p2)
}
func7个_new函数1() {
	//基本数据类型(整型浮点型,字符串,布尔,数组,结构体,类型)属于值类型
	//值类型的特定:当声明未赋值之前存在一个默认值(zero value)
	var x int
	var name string
	fmt.Println(x, name)

	//指针类型属于引用类型,包括切片,map,channel都属于引用类型
	//引用类型当声明未赋值之前是没有开辟空间的,即没有默认值
	var p *int
	p = new(int)
	*p = 10
	fmt.Println(*p)
}

你可能感兴趣的:(Golang,golang,开发语言)