日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
聊聊Golang語言Method接收者使用值類型和指針類型

01介紹

在 Golang 語言中,function 的參數和 method 的接收者都可以選擇使用值傳遞和指針傳遞(“引用傳遞”),需要注意的是,其中指針傳遞是傳遞的指針值的副本,而不是指針指向的數據的副本。也就是說 Golang 語言和 C 系的所有語言相同,一切傳遞都是值傳遞。本文我們主要介紹 method 的接收者怎么選擇使用值類型和指針類型。

成都創(chuàng)新互聯(lián)公司服務項目包括高明網站建設、高明網站制作、高明網頁制作以及高明網絡營銷策劃等。多年來,我們專注于互聯(lián)網行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網行業(yè)的解決方案,高明網站推廣取得了明顯的社會效益與經濟效益。目前,我們服務的客戶以成都為中心已經輻射到高明省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!

02method 接收者的類型選擇

在使用關鍵字 type 定義的類型上定義 method,method 的接收者也可以作為 method 的參數,類似于 function 的參數,所以 method 的接收者和 function 參數一樣,我們也需要考慮選擇使用值類型和指針類型。

關于這個問題,我們通常會從兩方面去考慮,一是如果該 method 需要修改接收者,那么接收者必須使用指針類型;二是如果接收者占用的內存大小較大,出于性能考慮,我們也會選擇使用指針類型的接收者。

除此之外,我們還需考慮一致性。也就是說,如果該類型的某些 method 必須使用指針類型的接收者,其他 method 也應該使用指針類型的接收者。因此無論如何使用該類型,它的方法集都是一致的。

最后,如果接收者是基本類型,切片和小結構體,他們的值類型的內存占用較低,并且易讀。所以,該情況下除非 method 的語義需要必須使用指針類型的接收者,否則,我們可以選擇使用值類型的接收者。

 
 
 
 
  1. type User struct {
  2.  name string
  3. }
  4. func (u User) SetNameValueType(str string) {
  5.  fmt.Printf("SetNameValueType() pointer:%p\n", &u) // SetNameValueType() pointer:0xc000096240
  6.  u.name = str
  7. }
  8. func (u *User) SetNamePointerType(str string) {
  9.  fmt.Printf("SetNamePointerType() pointer:%p\n", u) // SetNamePointerType() pointer:0xc000096220
  10.  u.name = str
  11. }
  12. func main () {
  13.  user1 := &User{}
  14.  fmt.Printf("pointer:%p\n", user1) // pointer:0xc000096220
  15.  fmt.Println(user1) // &{}
  16.  user1.SetNameValueType("lucy")
  17.  fmt.Println(user1) // &{}
  18.  user1.SetNamePointerType("lily")
  19.  fmt.Println(user1) // &{lily}
  20. }

閱讀上面這段代碼,我們可以發(fā)現值類型的接收者,調用方拷貝了副本;指針類型的接收者,調用方未拷貝副本。

03復合類型

map 和 slice 值類似于指針:它們是包含指向底層 map 或 slice 數據的指針的描述符。復制 map 或 slice 值不會復制它指向的數據。需要注意的是,如果超過 slice 的容量,運行時會重新分配一個新內存地址。

map 源碼:

 
 
 
 
  1. type hmap struct {
  2.  count     int // # live cells == size of map.  Must be first (used by len() builtin)
  3.  flags     uint8
  4.  B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  5.  noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
  6.  hash0     uint32 // hash seed
  7.  buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  8.  oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  9.  nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
  10.  extra *mapextra // optional fields
  11. }

slice 源碼:

 
 
 
 
  1. type slice struct {
  2.  array unsafe.Pointer
  3.  len   int
  4.  cap   int
  5. }

示例代碼:

 
 
 
 
  1. func main () {
  2.  user1 := &User{}
  3.  fmt.Printf("pointer:%p\n", user1) // pointer:0xc000096220
  4.  fmt.Println(user1) // &{}
  5.  user1.SetNameValueType("lucy")
  6.  fmt.Println(user1) // &{}
  7.  user1.SetNamePointerType("lily")
  8.  fmt.Println(user1) // &{lily}
  9.  // m := make(map[int]int)
  10.  m := map[int]int{}
  11.  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180
  12.  m[0] = 1
  13.  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180
  14.  m[1] = 2
  15.  s := make([]int, 0, 1)
  16.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0
  17.  s = append(s, 1)
  18.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0
  19.  s = append(s, 2)
  20.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0b0
  21. }

閱讀上面這段代碼,我們可以發(fā)現 map 類型未分配新內存地址,使用 append 函數向 slice 中追加元素,當元素個數未超出其容量之前,slice 也未分配新內存地址。

關于接口類型,復制接口值將復制存儲在接口值中的對象。如果接口值持有一個結構體,則復制接口值會復制該結構體。如果接口值持有指針,則復制接口值會復制指針,但不會復制它指向的數據。

04值類型怎么避免拷貝副本

閱讀到這里,讀者朋友可能會簡單認為使用值類型會拷貝副本,使用指針類型不會拷貝副本。實際上,我們可以通過優(yōu)化代碼,在不改變語義的前提下,實現使用值類型也不會拷貝副本。

示例代碼:

 
 
 
 
  1. type User struct {
  2.  name string
  3. }
  4. func (u User) SetNameValueType(str string) {
  5.  fmt.Printf("SetNameValueType() pointer:%p\n", &u) // SetNameValueType() pointer:0xc000096240
  6.  u.name = str
  7. }
  8. func (u User) ValueSetName(str string) User {
  9.  u.name = str
  10.  return u
  11. }
  12. func main () {
  13.  user2 := &User{}
  14.  fmt.Printf("user2 pointer:%p\n", user2) // user2 pointer:0xc000010290
  15.  user2.SetNameValueType("tom") // SetNameValueType() pointer:0xc0000102a0
  16.  user3 := &User{}
  17.  fmt.Printf("user3 pointer:%p\n", user3) // user3 pointer:0xc0000102b0
  18.  user3.ValueSetName("bob")
  19.  fmt.Printf("pointer:%p\n", user3) // pointer:0xc0000102b0
  20. }

閱讀上面這段代碼,我們發(fā)現 User 的 SetNameValueType 方法和 ValueSetName 方法,二者都是值傳遞,但是 SetNameValueType 方法會拷貝副本,ValueSetName 方法不會拷貝副本。原因是我們給 ValueSetName 方法定義了一個 User 類型的返回值,從而避免了 ValueSetName 方法拷貝副本。

05總結

本文我們主要介紹了 method 的接收者使用值傳遞和指針傳遞的區(qū)別,并且講述了選擇使用值傳遞和指針傳遞需要考慮的決定因素,也指出了復合類型與值類型的區(qū)別。最后,使用一個簡單示例演示了通過優(yōu)化代碼,在不改變語義的前提下,怎么實現使用值類型也不會拷貝副本。

本文轉載自微信公眾號「Golang語言開發(fā)?!?,可以通過以下二維碼關注。轉載本文請聯(lián)系Golang語言開發(fā)棧公眾號。


文章題目:聊聊Golang語言Method接收者使用值類型和指針類型
標題網址:http://www.5511xx.com/article/dpoghje.html