Go高性能之方法接收器 - 指針vs值

示例

如果您是 Go 新手,那麼您一定遇到過方法和函數的概念。讓我們找出兩者之間的區別-

通過指定參數的類型、返回值和函數體來聲明函數。

type Person struct { 
    Name string 
    Age int 
}func NewPerson(name string, age int) *Person { 
  return &Person{ 
     Name: name, 
     Age: age, 
  } 
}

方法只是一個帶有接收器參數的函數。它使用相同的語法聲明,並添加了接收者

func (p *Person) isAdult bool { 
  return p.Age > 18 
}

在上面的方法聲明中,我們在類型上聲明瞭isAdult方法。*Person

現在我們將看到值接收器指針接收器之間的區別

值接收者複製類型並將其傳遞給函數。函數堆棧現在擁有一個相等的對象,但在內存上的不同位置。這意味着對傳遞的對象所做的任何更改都將保留在該方法的本地。原始對象將保持不變。

指針接收器將類型的地址傳遞給函數。函數堆棧具有對原始對象的引用。因此對傳遞對象的任何修改都會修改原始對象。

讓我們通過示例來理解這一點-

package main
import (
  "fmt"
)
type Person struct {
    Name string
    Age  int
}
func ValueReceiver(p Person) {
    p.Name = "John"
    fmt.Println("Inside ValueReceiver : ", p.Name)
}
func PointerReceiver(p *Person) {
    p.Age = 24
    fmt.Println("Inside PointerReceiver model: ", p.Age)
}
func main() {
    p := Person{"Tom", 28}
    p1:= &Person{"Patric", 68}
    ValueReceiver(p)
fmt.Println("Inside Main after value receiver : ", p.Name)
    PointerReceiver(p1)
fmt.Println("Inside Main after value receiver : ", p1.Age)
}

------------
Inside ValueReceiver :  John
Inside Main after value receiver :  Tom
Inside PointerReceiver :  24
Inside Main after pointer receiver :  24

這表明具有值接收者的方法修改了對象的副本,而原始對象保持不變。Like- 通過 ValueReceiver 方法將一個人的姓名從 Tom 更改爲 John,但這種更改並未反映在 main 方法中。另一方面,帶有指針接收器的方法會修改實際對象。Like- 通過 PointerReceiver 方法將人的年齡從 68 歲更改爲 24 歲,同樣的變化反映在 main 方法中。您可以通過在指針或值接收器操作之前和之後打印出對象的地址來檢查事實。

那麼如何在 Pointer 和 Value 接收器之間進行選擇呢?

如果要更改方法中接收器的狀態,操作它的值,請使用指針接收器。使用按值複製的值接收器是不可能的。對值接收器的任何修改對於該副本都是本地的。如果您不需要操作接收器值,請使用值接收器

指針接收器避免在每個方法調用上覆制值。如果接收器是一個大型結構,這可能會更有效,

值接收器是併發安全的,而指針接收器不是併發安全的。因此,程序員需要照顧它。

彙總:

  • 如果接收者是 map、func 或 chan,不要使用指向它的指針。
  • 儘量對所有方法使用相同的接收器類型。
  • 如果接收者是一個切片並且該方法沒有重新切片或重新分配切片,則不要使用指向它的指針。
  • 如果方法需要改變接收者,接收者必須是一個指針。
  • 如果接收者是包含sync.Mutex或類似同步字段的結構,則接收者必須是指針以避免複製。
  • 如果接收器是大型結構或數組,則指針接收器效率更高。大有多大?假設它相當於將其所有元素作爲參數傳遞給方法。如果感覺太大,那麼對於接收器來說也太大了。
  • 函數或方法是否可以同時或在從此方法調用時改變接收者?調用方法時,值類型會創建接收器的副本,因此外部更新不會應用於此接收器。如果更改必須在原始接收器中可見,則接收器必須是指針。
  • 如果接收器是結構體、數組或切片,並且它的任何元素都是指向可能發生變化的東西的指針,則更喜歡指針接收器,因爲它會使讀者更清楚意圖。
  • 如果接收者是一個小數組或結構,它自然是一個值類型(例如,類似time.Time類型),沒有可變字段和指針,或者只是一個簡單的基本類型,如 int 或 string,則值接收器更好
    值接收器可以減少可以生成的垃圾量;如果將值傳遞給值方法,則可以使用堆棧上的副本而不是在堆上分配。(編譯器試圖巧妙地避免這種分配,但它並不總是成功。)不要在沒有首先進行分析的情況下選擇值接收器類型。
  • 最後,當有疑問時,使用指針接收器。

 

原文: https://medium.com/globant/go-method-receiver-pointer-vs-value-ffc5ab7acdb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章