Golang 引用类型和值类型以及错误“as the method has a pointer receiver”

本文详细解析了Go语言中值传递与引用传递在heap结构中的区别,通过实例展示了如何实现heap接口和PersonWrapper结构,重点讲解了为何&heap可以调用不同类型的函数。同时介绍了方法集合的概念,以及Go中对象和指针对方法调用的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这方面优点杂,直接放链接

https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md
https://learnku.com/articles/45323
https://blog.youkuaiyun.com/timemachine119/article/details/54927121
第三个链接讲得糊里糊涂的,实际上这个就是值传参和引用传参的老问题,多说无益,我们用一个heap的例子做说明,
一个完整的heap struct 要实现那些方法呢,一共要求实现5个方法才能实现heap接口

type IntHeap []int  // 定义一个类型

func (h IntHeap) Len() int { return len(h) }  // 绑定len方法,返回长度
func (h IntHeap) Less(i, j int) bool {  // 绑定less方法
	return h[i] < h[j]  // 如果h[i]<h[j]生成的就是小根堆,如果h[i]>h[j]生成的就是大根堆
}
func (h IntHeap) Swap(i, j int) {  // 绑定swap方法,交换两个元素位置
	h[i], h[j] = h[j], h[i]
}

func (h *IntHeap) Pop() interface{} {  // 绑定pop方法,从最后拿出一个元素并返回
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

func (h *IntHeap) Push(x interface{}) {  // 绑定push方法,插入新元素
	*h = append(*h, x.(int))
}

可以看出前三个用的是intHeap,而最后两个用的是*intHeap类型。因为这里用的是切片(type IntHeap []int )对象是引用类型,所以可以直接用intHeap,因为golang提供的sort实际上是基于slice实现的,所以里面必然有引用形式的slice,而后面的heap用 *是一种习惯性质的做法,避免内部的结构体传值传参问题。更复杂的例子:

package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string    // 姓名
    Age  int    // 年纪
}
 
type PersonWrapper struct {
    people [] Person
    by func(p, q * Person) bool
}
 
func (pw PersonWrapper) Len() int {    // 重写 Len() 方法
    return len(pw.people)
}
func (pw PersonWrapper) Swap(i, j int){     // 重写 Swap() 方法
    pw.people[i], pw.people[j] = pw.people[j], pw.people[i]
}
func (pw PersonWrapper) Less(i, j int) bool {    // 重写 Less() 方法
    return pw.by(&pw.people[i], &pw.people[j])
}
 
func main() {
    people := [] Person{
        {"zhang san", 12},
        {"li si", 30},
        {"wang wu", 52},
        {"zhao liu", 26},
    }
 
    fmt.Println(people)
 
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return q.Age < p.Age    // Age 递减排序
    }})
 
    fmt.Println(people)
    sort.Sort(PersonWrapper{people, func (p, q *Person) bool {
        return p.Name < q.Name    // Name 递增排序
    }})
 
    fmt.Println(people)
 
}

那么为什么&heap可以调用不管是引用还是值类型的方法呢?
这里就需要提到golang中方法集合的概念,一个struct虽然可以通过值类型和引用类型两种方式定义方法,但是不通的对象类型对应了不同的方法集:

Values                    Methods Receivers
-----------------------------------------------
 T                        (t T)
*T                        (t T) and (t *T) 

当你的实例是对象的时候只能调用(t T) 结构的方法,而当你的实例是对象指针的时候就可以调用这两种了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值