Go语言 指针总结

虾米哥 阅读:231 2021-05-02 13:51:21 评论:0

指针

  本章围绕字符串、数字、数组、切片、map、channel、结构体与指针赋值及函数传参的应用剖析

字符串

字符串本身也是StringHeader的结构体,包含Data指针与字符串长度,如下

type StringHeader struct { 
    Data uintptr 
    Len  int 
}

Data指向的内存地址不可更改,字符串赋值和传参只是拷贝了StringHeader中Data和Len的值

package main 
 
import "fmt" 
 
func main()  { 
	str := "Hello World!" 
	var data string 
	data = str 
	// 拷贝str中Data与Len 
	fmt.Println(data) 
	data = "Hello Go!" 
	// 修改data的值 在内存中生成新的StringHeader结构体 并赋值给data 
	fmt.Println(data) 
	// str内存未改变 
	fmt.Println(str) 
} 
 
//Hello World! 
//Hello Go! 
//Hello World!

当声明变量为字符串指针时,变量赋值时对象一定是字符串内存地址,函数传参时拷贝的也是内存地址而已 

package main 
 
import "fmt" 
 
 
func main()  { 
	str := "Hello World!" 
	var ptr *string 
	// 错误方法 str是字符串类型非指针类型 
	//ptr = str 
	// 正确方式 获取str的地址 赋值给ptr 
	ptr = &str 
 
	fmt.Println(ptr) 
	fmt.Println(*ptr) 
} 
 
//0xc0000421c0 
//Hello World! 

  

 数字

数字未找到对应的结构体,数字类型赋值、指针、函数传参与字符串一致,不可修改(修改等同于重新赋值)

package main 
 
import "fmt" 
 
func main()  { 
 
	number := 10 
	var ptr *int 
	// 错误方法 str是字符串类型非指针类型 
	//ptr = str 
	// 正确方式 获取str的地址 赋值给ptr 
	ptr = &number 
 
	fmt.Println(ptr) 
	fmt.Println(*ptr) 
} 
 
//0xc00000a0b8 
//10 

  

 数组

数组赋值、函数传参时,进行都是内存拷贝,数据都会拷贝一份,新的数组修改不影响被赋值的数组

package main 
 
import "fmt" 
 
func main()  { 
	list1 := [4] int{1,2,3,4} 
 
	list2 := list1 
	list2[0] =100 
	fmt.Println(list1) 
	fmt.Println(list2) 
} 
 
//[1 2 3 4] 
//[100 2 3 4]

数组指针,指针修改时不需要加*的;修改时,原数组更改

package main 
 
import "fmt" 
 
func main()  { 
	list := [4]int{1,2,3,4} 
	// 声明时指定数组大小 
	var ptr *[4]int 
	ptr = &list 
	// 错误赋值 
	//*ptr[0] =100 
	// 正确方式 
	ptr[0] = 100 
	fmt.Println(list) 
	fmt.Println(*ptr) 
} 
 
//[100 2 3 4] 
//[100 2 3 4] 

切片

切片结构体 SliceHeader 如下

type SliceHeader struct { 
    // 指向数组内存地址 赋值时拷贝的是数组地址 
    Data uintptr 
    // 长度 
    Len  int 
    // 申请空间 
    Cap  int 
} 

赋值、copy、函数传参时只是拷贝了结构体中的变量。详情Go语言【数据结构】切片

package main 
 
import "fmt" 
 
func main()  { 
	slice1 := []int{1,2,3,4} 
 
	slice2 := slice1 
	slice2[0] =100 
	fmt.Println(slice1) 
	fmt.Println(slice2) 
} 
 
//[100 2 3 4] 
//[100 2 3 4] 

 切片指针,下面方式都不可以修改

package main 
 
import "fmt" 
 
func main() { 
	slice1 := []int{1,2,3,4} 
	var ptr *[]int 
	ptr = &slice1 
 
	// 下面两种方式都不可以修改 
	ptr[0] =100 
	*ptr[0] =100 
	fmt.Println(slice1) 
	fmt.Println(*ptr) 
} 
 
//[1 2 3 4] 
//[1 2 3 4] 

  

channel

通道在赋值时,指向的都是同一块内存地址

package main 
 
import "fmt" 
 
func main() { 
	 chan1 := make(chan string,1) 
	 chan2 := chan1 
	 chan2 <- "hello" 
	 data := <-chan1 
	 fmt.Println(data) 
	 // 指向同一块地址 
	 fmt.Println(chan1) 
	 fmt.Println(chan2) 
} 
 
//hello 
//0xc000088000 
//0xc000088000

同时,通道也支持指针

package main 
 
import "fmt" 
 
func main() { 
	 chan1 := make(chan string,1) 
	 chan2 := &chan1 
	 *chan2 <- "hello" 
	 data := <-chan1 
	 fmt.Println(data) 
	 fmt.Println(chan1) 
	 fmt.Println(chan2) 
} 
 
//hello 
//0xc000038060 
//0xc000006028 

  

结构体 

那么重点来了,结构体赋值和指针有何区别,先看戏结构体生成的三种方式,其中第二种方式和第三中方式一致

package main 
 
import "fmt" 
 
type Phone struct { 
	color string 
	name string 
} 
 
func main() { 
	// 第一种生成方式  生成结构体对象 
	phone1 :=Phone{"Red","Iphone"} 
	fmt.Println(phone1.color) 
	fmt.Println(phone1.name) 
	fmt.Println(phone1) 
 
	// 第二种生成方式  生成结构体指针 
	phone2 :=&Phone{"Red","Iphone"} 
	fmt.Println(phone2.color) 
	fmt.Println(phone2.name) 
	fmt.Println(phone2) 
 
	// 第三种生成方式  生成结构体指针 
	phone3 := new(Phone) 
	phone3.color = "Red" 
	phone3.name = "Iphone" 
	fmt.Println(phone3.color) 
	fmt.Println(phone3.name) 
	fmt.Println(phone3) 
} 
 
//Red 
//Iphone 
//{Red Iphone} 
//Red 
//Iphone 
//&{Red Iphone} 
//Red 
//Iphone 
//&{Red Iphone}

结构体赋值,等同于拷贝了结构体中的变量,函数传参与赋值一样

package main 
 
import "fmt" 
 
type Phone struct { 
	color string 
	name string 
} 
 
func main() { 
	// 赋值 
	phone1 :=Phone{"Red","Iphone"} 
 
	phone2 := phone1 
	phone2.color = "Green" 
	fmt.Println(phone1.color) 
	fmt.Println(phone2.color) 
} 
 
//Red 
//Green

 而指针只是拷贝了结构体的内存地址,修改会影响原来的值

package main 
 
import "fmt" 
 
type Phone struct { 
	color string 
	name string 
} 
 
func main() { 
	// 赋值 
	phone1 :=&Phone{"Red","Iphone"} 
 
	phone2 := phone1 
	phone2.color = "Green" 
	fmt.Println(phone1.color) 
	fmt.Println(phone2.color) 
} 
 
//Green 
//Green 

  


声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
排行榜
KIKK导航

KIKK导航

关注我们