go的"引用传递"

200 阅读3分钟

1.链表改变头指针和返回投指针

package main

import "fmt"

type Node struct {
	num  int
	next *Node
}

func main() {
	n := 0
	fmt.Scan(&n)
	head := &Node{-1, nil}
	tmp := head
	for i := 1; i <= n; i++ {
		tmp.next = &Node{i, nil}
		tmp = tmp.next
	}
	head = head.next
	reverse(head)
	//head = reverse1(head)
	Print(head)
}

func reverse(head *Node) {
	first := head
	second := head.next
	head.next = nil
	for second != nil {
		tmp := second
		second = second.next
		tmp.next = first
		first = tmp
	}
	head = first
}
func reverse1(head *Node) *Node {
	first := head
	second := head.next
	head.next = nil
	for second != nil {
		tmp := second
		second = second.next
		tmp.next = first
		first = tmp
	}
	head = first
	return head
}
func Print(head *Node) {
	tmp := head
	for tmp != nil {
		fmt.Printf("%d ", tmp.num)
		tmp = tmp.next
	}
	fmt.Println()
}

上面的区别主要在于我是直接改编原头指针的指向还是返回一个新指针后在main函数中改变指向

image-20240907222425561转存失败,建议直接上传图片文件

image-20240907222448885转存失败,建议直接上传图片文件

通过编译分析发现head首先就是main函数中的地址,通过赋值之后指向最后一个元素,但是函数返回之后还是指向第一个元素,也就是说,在函数内部改变指针的指向是没有用的

这么说go的指针是值传递,不是引用传递?

事实上说,go语言是没有引用传递的,go语言之所以可以达到引用传递的效果,实际上是这些数据结构底层的指针指向同一片内存地址,从而达到看似引用传递的效果.

所以说在函数内部不能修改指针的指向?

是的,指针本质上就是一个内存地址,也就是一个8位或者4位的二进制数,这个地址在函数传递的时侯其实也是传递的一份副本,只不过指向同一片内存,对这个内存的修改对其他函数也可见.例如,如果切片在函数中发送了阔容,函数外的切片孩是不会变化的

package main

import "fmt"

func main() {
	s := make([]int, 1, 3)
	//s := make([]int, 1, 20)
	fmt.Printf("cap:%d len:%d arrs:%p \n", cap(s), len(s), &s[0])
	extendSlice(s)
	fmt.Printf("cap:%d len:%d arrs:%p \n", cap(s), len(s), &s[0])
}
func extendSlice(s []int) {
	fmt.Printf("cap:%d len:%d arrs:%p \n", cap(s), len(s), &s[0])
	for i := 0; i < 7; i++ {
		s = append(s, i)
	}
	fmt.Printf("cap:%d len:%d arrs:%p \n", cap(s), len(s), &s[0])
}
//stdin
//cap:3 len:1 arrs:0xc00001c198 
//cap:3 len:1 arrs:0xc00001c198 
//cap:12 len:8 arrs:0xc000028240 
//cap:3 len:1 arrs:0xc00001c198 



既然说到这里了,go语言还有个unsafe.Pointer,这个有什么区别?

首先看看unsafe.Pointer的结构

//这里就不放官方解释了,感兴趣的去看源码
//大概意思是unsafe.Pointer可以表示任意类型的指针,也可以转成任意类型,并绕过类型检察读写其内存值
type Pointer *ArbitraryType

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package. It represents the type of an arbitrary Go expression.
//大概意思是这个结构体属于任意类型
type ArbitraryType int

unsafe.Pointer的作用主要就是跳过类型检测修改一些数据,但是在实际的开发中并不建议这样做,因为不好维护而且容易出bug