Golang中接收器的理解问题求助

Golang中接收器的理解问题求助 我正在学习一门Go语言的在线课程。在方法讨论中遇到接收器这个概念时,之前理解得还不错的内容突然变得难以理解了。有人能试着解释一下它们的工作原理以及在实际编程中如何运用吗?除了学过一些Python和在高中时期接触过基础的BASIC语言外,这是我第一次深入涉足编程领域!

7 回复

哈哈。感谢你的救援 😉

太好了 😊

更多关于Golang中接收器的理解问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢详细的解释。Go 语言既不能被视为函数式语言,也不能被视为面向对象语言,但它具备了两者的大部分能力和特性。

我之前认为它更接近函数式语言,所以将其归类为函数式语言。最近我才了解到"多范式编程语言"这个术语,而这正是 Go 语言的定位。

方法接收器定义了方法与哪种结构体类型相关联,以及这种关联应如何处理。Go语言中有两种类型的接收器:值接收器和指针接收器。值接收器获取结构体数据的副本,但无法修改原始数据;而指针接收器允许直接访问结构体本身。

关于方法的更多深入细节,请参阅Go语言之旅:https://tour.golang.org/methods/1

从高层次来看,

Go 是一门函数式编程语言,但它也具备面向对象编程(OOP)的特性。
如果你了解 OOP,就会知道其中包含具有自身变量和方法的类和对象。

Go 中的结构体和方法与此类似。你可以将结构体视为对象,方法的工作方式也相同。接收器就相当于对象。
不过,请不要完全照搬我所说的内容。如果你有 OOP 的基础知识,这只是一个帮助你理解的理论。

正如 CurtGreen 所说,接收器可以分为值接收器和指针接收器。
你找不到比这更好的定义了 😊

Method receivers define what struct type a method is associated with and how that relationship should be treated

@abhayanoop

维基百科关于 Go 语言的描述称其为

多范式:并发式、函数式、面向对象式、过程式

考虑到这个列表,我认为倒着读会更容易理解。表情

20世纪60年代存在的语言大多是过程式语言,包括 Fortran、Algol、Basic、Pascal 和 C。Pascal 和 C 都基于 Algol,而 Go 又基于这些语言。

过程式编程 - 维基百科

我认为 Go 是一种过程式语言,同时具备面向对象编程、函数式编程和并发编程的一些现代特性。

引用 abhayanoop 的话:

Go 是一门函数式编程语言

事实并非如此。

有人可能会这么说,但即便函数可以作为返回值或参数传递,实际操作起来仍感觉别扭且笨拙。

我很少看到真正运用函数式范式或特别是高阶函数的代码。

在 Go 中,即使是最简单的高阶函数也几乎没什么用处,尤其是缺乏泛型或模板支持,导致你不得不为不同的类型签名大量重复编写代码。

试想一下 Haskell 中的 idconst 函数:

id :: a -> a
id x = x

const :: b -> a -> b
const b = \_ -> b -- 真正的 Haskell 程序员可能会用不同方式实现,这里只是为了更便于与下面的 Go 代码对比。

在 Go 中实现会是这样的:

func id(x int) int { return x } // 这个还算可读,但仅限于 int 类型,继续为其他所有类型重复编写,不要用 interface{},因为那样会让情况更糟…

func const(a int) func(b int)int {
  return func(b int) int { return a }
}

现在再尝试实现更有用的高阶函数,比如 mapreduce

附注:真正的函数式语言会更注重尾调用优化,而不是人为限制调用栈深度…

在Go语言中,接收器(receiver)是定义方法时的一个关键概念,它允许你将函数与特定类型绑定,从而创建方法。接收器类似于其他面向对象语言中的"this"或"self",但Go的实现方式更灵活。

接收器有两种类型:

  1. 值接收器(value receiver) - 操作接收器的副本
  2. 指针接收器(pointer receiver) - 操作接收器本身

基本语法:

func (receiver receiverType) methodName(parameters) returnType {
    // 方法实现
}

示例代码:

package main

import "fmt"

// 定义一个结构体类型
type Rectangle struct {
    width, height float64
}

// 值接收器方法 - 计算面积
func (r Rectangle) Area() float64 {
    return r.width * r.height
}

// 指针接收器方法 - 修改尺寸
func (r *Rectangle) Scale(factor float64) {
    r.width *= factor
    r.height *= factor
}

// 值接收器方法 - 创建副本并缩放
func (r Rectangle) ScaledCopy(factor float64) Rectangle {
    return Rectangle{
        width:  r.width * factor,
        height: r.height * factor,
    }
}

func main() {
    // 创建矩形实例
    rect := Rectangle{width: 10, height: 5}
    
    fmt.Printf("原始矩形: %.1f x %.1f\n", rect.width, rect.height)
    fmt.Printf("面积: %.1f\n", rect.Area())
    
    // 使用指针接收器修改原对象
    rect.Scale(2)
    fmt.Printf("缩放后: %.1f x %.1f\n", rect.width, rect.height)
    
    // 使用值接收器创建副本
    newRect := rect.ScaledCopy(0.5)
    fmt.Printf("副本矩形: %.1f x %.1f\n", newRect.width, newRect.height)
    fmt.Printf("原矩形保持不变: %.1f x %.1f\n", rect.width, rect.height)
}

输出结果:

原始矩形: 10.0 x 5.0
面积: 50.0
缩放后: 20.0 x 10.0
副本矩形: 10.0 x 5.0
原矩形保持不变: 20.0 x 10.0

接收器类型的选择原则:

  1. 使用指针接收器的情况:
    • 需要修改接收器指向的值
    • 结构体较大,避免复制的开销
    • 方法需要修改接收器的状态
type Counter struct {
    value int
}

// 指针接收器 - 修改计数器值
func (c *Counter) Increment() {
    c.value++
}

// 指针接收器 - 重置计数器
func (c *Counter) Reset() {
    c.value = 0
}
  1. 使用值接收器的情况:
    • 不需要修改接收器
    • 类型是小型结构体或基本类型
    • 方法应该是无副作用的
type Point struct {
    x, y int
}

// 值接收器 - 计算距离,不修改原对象
func (p Point) DistanceTo(other Point) float64 {
    dx := float64(p.x - other.x)
    dy := float64(p.y - other.y)
    return math.Sqrt(dx*dx + dy*dy)
}

接口实现中的接收器:

type Shape interface {
    Area() float64
    Perimeter() float64
}

// Rectangle 实现 Shape 接口
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.width + r.height)
}

// 可以在接口类型上调用方法
func printShapeInfo(s Shape) {
    fmt.Printf("面积: %.1f, 周长: %.1f\n", s.Area(), s.Perimeter())
}

接收器让Go语言在保持简洁性的同时提供了面向对象编程的能力,通过合理选择接收器类型,可以编写出高效且易于维护的代码。

回到顶部