2.12. 补充注意事项 10 最好不要在结构体中定义 `pointer receiver` 的方法

未匹配的标注

g g study,d d up!

补充注意事项 10

最好不要在结构体中定义 pointer receiver 的方法

补充注意事项 10 最好不要在结构体中定义 `pointer receiver` 的方法

10. 最好不要在结构体中定义 pointer receiver 的方法,以避免使用者对结构体进行无意中的修改。如果需要对结构体进行修改,可以使用 value receiver 的方法。

在 Go 中,方法可以是值接收器或指针接收器。使用值接收器时,方法接收器是值的副本,因此方法对值的修改不会影响原始值。使用指针接收器时,方法接收器是指针,因此方法对指针指向的值进行修改,将影响原始值。

如果一个结构体类型的方法使用指针接收器,它允许在调用该方法时修改结构体实例的字段。如果使用值接收器,方法将无法修改结构体实例的字段,因为它们只是值的副本。因此,在设计结构体类型时,应该根据使用情况选择正确的接收器类型,以确保结构体实例的正确性和安全性。

如果结构体类型中的方法使用指针接收器,并且使用者对该结构体实例的指针进行了修改,那么这可能会导致未知的副作用和竞态条件。因此,最好不要在结构体类型中定义指针接收器的方法,除非有充分的理由需要这样做,并且应该确保使用者了解这些方法的影响和安全性。

相反,如果结构体类型中的方法使用值接收器,使用者可以安全地复制结构体实例,而不必担心在修改原始实例时发生意外的更改。因此,在结构体类型中定义值接收器的方法是一个更好的选择,以避免对结构体实例的无意中修改。

下面是一个使用值接收器的例子,用于在结构体中存储和获取学生的成绩信息:

package main

import "fmt"

type Student struct {
    Name    string
    Scores  []int
    Avg     float64
}

func (s Student) AddScore(score int) {
    s.Scores = append(s.Scores, score)
}

func (s Student) CalculateAverage() {
    sum := 0
    for _, score := range s.Scores {
        sum += score
    }
    s.Avg = float64(sum) / float64(len(s.Scores))
}

func (s *Student) CalculateAveragePoint() {
  sum := 0
  for _, score := range s.Scores {
  sum += score
  }
  s.Avg = float64(sum) / float64(len(s.Scores))
}

func main() {
    student := Student{Name: "Tom", Scores: []int{80, 90, 85}}
    student.AddScore(95)
    student.CalculateAverage()
    fmt.Println(student.Name, student.Scores, student.Avg)

    fmt.Println("--------------------------teacher------------------")
    // 传入指针
    teacher := Student{Name: "Tom", Scores: []int{80, 90, 85}}
    teacher.CalculateAveragePoint()
    fmt.Println(teacher.Name, teacher.Scores, teacher.Avg)
}

在上面的例子中,AddScoreCalculateAverage 方法都使用值接收器。在 AddScore 方法中,我们试图向 Scores 切片中添加一个新的成绩。但是,在这个方法中,我们实际上并没有修改原始结构体中的 Scores 字段,因为 s 是值的副本,而不是原始结构体的引用。这意味着我们向 s.Scores 添加的新分数仅影响值接收器 s,而不是原始结构体中的 Scores 字段。因此,在主函数中输出的 Scores 字段仍然是 []int{80, 90, 85}

CalculateAverage 方法中,我们试图计算学生的平均分数。但是,与 AddScore 方法一样,我们无法修改原始结构体中的 Avg 字段。因此,在主函数中输出的 Avg 字段仍然是 0.0

因此,在这种情况下,使用值接收器的方法不能修改原始结构体的字段,我们应该使用指针接收器的方法,以便我们能够修改结构体的字段。

CalculateAveragePoint 就是使用指针。
输出结果如下:

λ go run test.go
Tom [80 90 85] 0
--------------------------teacher------------------
Tom [80 90 85] 85

欢迎关注公众号上海php自学中心,一起交流。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~