中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Golang 語言 Method 接收者使用值類型和指針類型

發布時間:2021-06-16 10:14:42 來源:億速云 閱讀:127 作者:chen 欄目:編程語言

本篇內容主要講解“如何理解Golang 語言 Method 接收者使用值類型和指針類型”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何理解Golang 語言 Method 接收者使用值類型和指針類型”吧!

01介紹

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

02method 接收者的類型選擇

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

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

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

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

type User struct {  name string }  func (u User) SetNameValueType(str string) {  fmt.Printf("SetNameValueType() pointer:%p\n", &u) // SetNameValueType() pointer:0xc000096240  u.name = str }  func (u *User) SetNamePointerType(str string) {  fmt.Printf("SetNamePointerType() pointer:%p\n", u) // SetNamePointerType() pointer:0xc000096220  u.name = str }  func main () {  user1 := &User{}  fmt.Printf("pointer:%p\n", user1) // pointer:0xc000096220  fmt.Println(user1) // &{}  user1.SetNameValueType("lucy")  fmt.Println(user1) // &{}  user1.SetNamePointerType("lily")  fmt.Println(user1) // &{lily} }

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

03復合類型

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

map 源碼:

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

slice 源碼:

type slice struct {  array unsafe.Pointer  len   int  cap   int }

示例代碼:

func main () {  user1 := &User{}  fmt.Printf("pointer:%p\n", user1) // pointer:0xc000096220  fmt.Println(user1) // &{}  user1.SetNameValueType("lucy")  fmt.Println(user1) // &{}  user1.SetNamePointerType("lily")  fmt.Println(user1) // &{lily}   // m := make(map[int]int)  m := map[int]int{}  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180  m[0] = 1  fmt.Printf("map pointer:%p\n", m) // map pointer:0xc000100180  m[1] = 2   s := make([]int, 0, 1)  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0  s = append(s, 1)  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0a0  s = append(s, 2)  fmt.Printf("slice pointer:%p\n", s) // slice pointer:0xc00001c0b0 }

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

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

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

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

示例代碼:

type User struct {  name string }  func (u User) SetNameValueType(str string) {  fmt.Printf("SetNameValueType() pointer:%p\n", &u) // SetNameValueType() pointer:0xc000096240  u.name = str }  func (u User) ValueSetName(str string) User {  u.name = str  return u }  func main () {  user2 := &User{}  fmt.Printf("user2 pointer:%p\n", user2) // user2 pointer:0xc000010290  user2.SetNameValueType("tom") // SetNameValueType() pointer:0xc0000102a0   user3 := &User{}  fmt.Printf("user3 pointer:%p\n", user3) // user3 pointer:0xc0000102b0  user3.ValueSetName("bob")  fmt.Printf("pointer:%p\n", user3) // pointer:0xc0000102b0 }

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

05總結

本文我們主要介紹了 method  的接收者使用值傳遞和指針傳遞的區別,并且講述了選擇使用值傳遞和指針傳遞需要考慮的決定因素,也指出了復合類型與值類型的區別。

到此,相信大家對“如何理解Golang 語言 Method 接收者使用值類型和指針類型”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

广水市| 海淀区| 浠水县| 临沧市| 株洲县| 三河市| 金塔县| 泗阳县| 凤冈县| 莫力| 平阴县| 张掖市| 连平县| 镶黄旗| 婺源县| 铜川市| 博湖县| 石景山区| 新巴尔虎右旗| 金门县| 延津县| 明光市| 台州市| 化隆| 古交市| 余江县| 葫芦岛市| 万荣县| 贡觉县| 枣阳市| 常山县| 和田市| 万年县| 安顺市| 肇州县| 潮州市| 衡水市| 宜黄县| 孟村| 肇东市| 夏津县|