记一次Golang传参特性的实录&思考

记一次Golang的传参特性思考:
周末本来想实现一次简单的链表头插操作,在链表增加元素时,一开始写出了以下代码:

package main

import "fmt"

type MyLinkedList struct {
    Val  int
    Next *MyLinkedList
}

func Constructor() *MyLinkedList {
    return &MyLinkedList{
        Val:  0,
        Next: nil,
    }
}

func (this *MyLinkedList) Get(index int) int {
    head := this
    for i := 0; i < index; i++ {
        if head.Next == nil {
            return -1
        }
        head = head.Next
    }
    return head.Val
}

func (this *MyLinkedList) AddAtHead(val int) {
    newHead := &MyLinkedList{
        Val:  val,
        Next: this,
    }
    this = newHead
    return
}

func main() {
    demo := Constructor()
    demo.AddAtHead(7)
    demo.AddAtHead(2)
    fmt.Println(demo.Get(0))
}

  

头插法,即每次生成新的节点指向当前头,然后再把头向前移。
所以我这里新节点即为newhead,向前移的这一步,我写为了this = newHead
但是发现最终打印出Get(0)仍然是0,头插法没有生效吗?

这里思考了一段时间,也向别人请教一些后,打印出了main函数里的地址,和AddAtHead函数里this指针的地址:

这两者是不一样的,Golang对象传递也是值传递,this指针和原有对象并不是一个地址,而是把原有对象内的内容复制了一份!
所以在函数AddAtHead里,即使改变this指针的内容,对原有对象也是不会有影响的,
事实上,在对象自己的方法里,想要通过this指针来改变原有对象的指向,是无法实现的。
只能改变指针指向的内容,不能改变指针自身

那么凭现有代码,应该如何重新实现头插法呢?
计算机科学里,有一句名言:
计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决
既然无法通过自身改变,那我就把自身加一个中间层————指针
这样就通过改变指针指向的内容,来将头结点完成前移了,

新增了“中间层”的代码如下:

type MyLinkedList struct {
	*ListNode
}

type ListNode struct {
	Val  int
	Next *ListNode
}

func Constructor() *MyLinkedList {
	head := &ListNode{Next: nil}
	return &MyLinkedList{head}
}

func (this *MyLinkedList) Get(index int) int {
	head := this.ListNode
	for i := 0; i < index; i++ {
		if head.Next == nil {
			return -1
		}
		head = head.Next
	}
	return head.Val
}

func (this *MyLinkedList) AddAtHead(val int) {
	newNode := &ListNode{
		Val:  val,
		Next: this.ListNode,
	}
	this.ListNode = newNode
	return
}

func main() {
	demo := Constructor()
	demo.AddAtHead(7)
	demo.AddAtHead(2)
	demo.AddAtHead(1)

	fmt.Println(demo.Get(0))
}

  

Bingo了,这次内容符合预期!

posted @ 2022-03-08 16:28  J0nathan1ei  阅读(63)  评论(0)    收藏  举报