成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊Golang 語言 Method 接收者使用值類型和指針類型

開發(fā) 后端
在 Golang 語言中,function 的參數(shù)和 method 的接收者都可以選擇使用值傳遞和指針傳遞(“引用傳遞”),需要注意的是,其中指針傳遞是傳遞的指針值的副本,而不是指針指向的數(shù)據(jù)的副本。

[[403074]]

01介紹

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

02method 接收者的類型選擇

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

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

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

最后,如果接收者是基本類型,切片和小結(jié)構(gòu)體,他們的值類型的內(nèi)存占用較低,并且易讀。所以,該情況下除非 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} 

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

03復合類型

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

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.  
  8.  buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. 
  9.  oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing 
  10.  nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated) 
  11.  
  12.  extra *mapextra // optional fields 

slice 源碼:

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

示例代碼:

  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.  
  10.  // m := make(map[int]int
  11.  m := map[int]int{} 
  12.  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180 
  13.  m[0] = 1 
  14.  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180 
  15.  m[1] = 2 
  16.  
  17.  s := make([]int, 0, 1) 
  18.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0 
  19.  s = append(s, 1) 
  20.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0 
  21.  s = append(s, 2) 
  22.  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0b0 

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

關(guān)于接口類型,復制接口值將復制存儲在接口值中的對象。如果接口值持有一個結(jié)構(gòu)體,則復制接口值會復制該結(jié)構(gòu)體。如果接口值持有指針,則復制接口值會復制指針,但不會復制它指向的數(shù)據(jù)。

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

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

示例代碼:

  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.  
  17.  user3 := &User{} 
  18.  fmt.Printf("user3 pointer:%p\n", user3) // user3 pointer:0xc0000102b0 
  19.  user3.ValueSetName("bob"
  20.  fmt.Printf("pointer:%p\n", user3) // pointer:0xc0000102b0 

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

05總結(jié)

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

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

 

責任編輯:武曉燕 來源: Golang語言開發(fā)棧
相關(guān)推薦

2022-06-01 09:51:51

Golang方法接收者

2022-01-09 23:04:19

語言打印結(jié)構(gòu)體

2021-04-16 07:19:04

Hive數(shù)據(jù)類型Hql

2023-07-16 23:43:05

Go語言模式

2023-03-07 10:32:34

Go語言結(jié)構(gòu)體

2009-08-31 14:34:46

C#值類型C#結(jié)構(gòu)類型

2009-10-10 09:53:07

.NET值類型

2009-08-19 16:39:44

C#值類型C#引用類型

2009-08-26 14:05:19

C#值類型和引用類型

2021-11-14 23:05:28

GoCast語言

2021-08-27 07:47:06

引用類型

2021-09-18 10:15:00

CIO首席信息官IT主管

2024-08-12 08:50:17

2025-05-20 08:10:00

函數(shù)函數(shù)類型函數(shù)指針類型

2021-09-02 12:10:52

Go語言枚舉類型

2022-05-11 09:01:54

Swift類型系統(tǒng)幻象類型

2022-03-29 08:30:47

指針數(shù)組C語言

2022-06-17 06:23:23

Oracle壓縮類型

2022-10-24 00:03:26

GolangNew函數(shù)

2022-06-13 09:02:06

Swift類型占位符
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品99久久久久久久久 | 国产一区二区三区四区 | 91精品国产99| 超碰在线久 | 国产成人在线一区二区 | 一区二区三区欧美在线 | 中文字幕视频在线观看 | 欧美黄色网| 免费一区二区三区 | 色呦呦在线 | 99精品欧美一区二区三区综合在线 | 国产精品久久久久久模特 | 亚洲欧美日韩系列 | 国产精品久久久久久久白浊 | 99精品欧美一区二区三区综合在线 | 亚洲欧美一区二区三区国产精品 | 欧美亚洲在线视频 | 久久久.com| 国产一级一片免费播放 | 久久国产成人午夜av影院武则天 | 91嫩草精品| 午夜视频在线观看网站 | 一级做a爰片久久毛片 | 日本黄色免费大片 | 九九久视频 | 日本二区在线观看 | 中文字幕亚洲一区二区三区 | 亚洲风情在线观看 | 毛片久久久 | 精品福利在线视频 | 日本黄色免费视频 | 成人精品视频免费 | 超碰成人在线观看 | 久久久久久久久91 | 在线精品亚洲欧美日韩国产 | 日本精品视频一区二区 | 美女三区| 久久国 | 亚洲美女av网站 | 特级特黄特色的免费大片 | 99久久99|