自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看完這期圖解,別再搞不清切片拷貝了

開發(fā) 后端
在剛使用 Go 時,菜刀曾將 Python 深拷貝手法[:]用于 Go 中 ,結(jié)果造成了 bug。相信不少轉(zhuǎn)語言的 Gopher 也在切片拷貝上栽過跟頭。

[[438643]]

本文轉(zhuǎn)載自微信公眾號「Golang技術(shù)分享」,作者機器鈴砍菜刀 。轉(zhuǎn)載本文請聯(lián)系Golang技術(shù)分享公眾號。

在剛使用 Go 時,菜刀曾將 Python 深拷貝手法[:]用于 Go 中 ,結(jié)果造成了 bug。相信不少轉(zhuǎn)語言的 Gopher 也在切片拷貝上栽過跟頭。

切片是 Go 中最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),之前我們談過切片傳遞、切換轉(zhuǎn)換、切片擴容等內(nèi)容。

本文,我們將探討切片拷貝,就切片的三種拷貝方式進行圖解分析,希望幫助讀者鞏固一下基礎(chǔ)知識。

深淺拷貝

所謂深淺拷貝,其實都是進行復(fù)制,主要區(qū)別在于復(fù)制出來的新對象和原來的對象,它們的數(shù)據(jù)發(fā)生改變時,是否會相互影響。

簡單而言,B 復(fù)制 A,如果 A 的數(shù)據(jù)發(fā)生變化,B 也跟著變化,這是淺拷貝。反之, 如果 B 不發(fā)生變化,則為深拷貝。

深淺拷貝差異的根本原因在于,復(fù)制出來的對象與原對象是否會指向同一個地址。

以下是 Python 中 list 與 Go 中 slice 深淺拷貝的表現(xiàn)差異

  1. // Python 版 
  2. if __name__ == '__main__'
  3.     a = [1, 2, 3] 
  4.     b = a 
  5.     c = a[:] 
  6.     a[0] = 100 
  7.     print(a, b, c) // [100, 2, 3] [100, 2, 3] [1, 2, 3] 
  8.  
  9. // Golang 版 
  10. func main() { 
  11.  a := []int{1, 2, 3} 
  12.  b := a 
  13.  c := a[:] 
  14.  a[0] = 100 
  15.  fmt.Println(a, b, c) // [100 2 3] [100 2 3] [100 2 3] 

發(fā)現(xiàn)沒有?在 Go 中 [:] 操作并不是深拷貝。

= 拷貝

通過=操作符拷貝切片,這是淺拷貝。

  1. func main() { 
  2.  a := []int{1, 2, 3} 
  3.  b := a 
  4.  fmt.Println(unsafe.Pointer(&a))  // 0xc00000c030 
  5.  fmt.Println(a, &a[0])            // [100 2 3] 0xc00001a078 
  6.  fmt.Println(unsafe.Pointer(&b))  // 0xc00000c048 
  7.  fmt.Println(b, &b[0])            // [100 2 3] 0xc00001a078 

圖解

[:] 拷貝

通過[:]方式復(fù)制切片,同樣是淺拷貝。

  1. func main() { 
  2.  a := []int{1, 2, 3} 
  3.  b := a[:] 
  4.  fmt.Println(unsafe.Pointer(&a)) // 0xc0000a4018 
  5.  fmt.Println(a, &a[0])           // [1 2 3] 0xc0000b4000 
  6.  fmt.Println(unsafe.Pointer(&b)) // 0xc0000a4030 
  7.  fmt.Println(b, &b[0])           // [1 2 3] 0xc0000b4000 

圖解

我們有時會使用[start: end]進行拷貝。例如,b:=a[1:],那它的拷貝情況如何

copy() 拷貝

上述兩種方式都是淺拷貝,如果要切片深拷貝,需要用到copy()內(nèi)置函數(shù)。

copy()函數(shù)簽名如下

  1. func copy(dst, src []Type) int 

其返回值代表切片中被拷貝的元素個數(shù)

  1. func main() { 
  2.  a := []int{1, 2, 3} 
  3.  b := make([]int, len(a), len(a)) 
  4.  copy(b, a) 
  5.  fmt.Println(unsafe.Pointer(&a))  // 0xc00000c030 
  6.  fmt.Println(a, &a[0])            // [1 2 3] 0xc00001a078 
  7.  fmt.Println(unsafe.Pointer(&b))  // 0xc00000c048 
  8.  fmt.Println(b, &b[0])            // [1 2 3] 0xc00001a090 

圖解

copy 的元素數(shù)量與原始切片和目標(biāo)切片的大小、容量有關(guān)系

  1. func main() { 
  2.  a := []int{1, 2, 3} 
  3.  b := []int{-1, -2, -3, -4} 
  4.  copy(b, a) 
  5.  fmt.Println(unsafe.Pointer(&a))  // 0xc0000a4018 
  6.  fmt.Println(a, &a[0])            // [1 2 3] 0xc0000b4000 
  7.  fmt.Println(unsafe.Pointer(&b))  // 0xc0000a4030 
  8.  fmt.Println(b, &b[0])            // [1 2 3 -4] 0xc0000aa060 

圖解

總結(jié)

切片是 Go 語言中最基本的數(shù)據(jù)結(jié)構(gòu),它的擴容與拷貝細節(jié),在理解不當(dāng)時,是很容易寫出程序 bug 的。

本文分別就切片的三種拷貝方式,=、[:]、copy()進行了探討。其中,=、[:]是淺拷貝,copy()拷貝是深拷貝。

 

這樣的圖解方式,你喜歡嗎~

 

責(zé)任編輯:武曉燕 來源: Golang技術(shù)分享
相關(guān)推薦

2017-08-09 15:07:08

大數(shù)據(jù)數(shù)據(jù)分析戶畫像

2021-06-16 00:57:16

JVM加載機制

2021-02-24 07:38:50

Redis

2025-04-21 10:43:21

2024-12-05 11:03:04

2022-05-27 21:56:55

索引存儲MySQL 存儲引擎

2021-03-18 23:28:45

Python反斜杠字符串

2020-12-01 11:33:57

Python拷貝copy

2015-02-28 10:01:00

云計算IT架構(gòu)虛擬化

2020-12-04 10:05:00

Pythonprint代碼

2020-12-02 11:18:50

print調(diào)試代碼Python

2020-06-18 10:48:44

Linux 系統(tǒng) 數(shù)據(jù)

2017-08-16 09:55:36

2023-08-18 15:22:54

工業(yè)物聯(lián)網(wǎng)工業(yè)互聯(lián)網(wǎng)

2021-06-09 06:41:11

OFFSETLIMIT分頁

2018-09-28 05:25:53

TopK算法代碼

2020-12-11 09:24:19

Elasticsear存儲數(shù)據(jù)

2025-02-05 08:02:31

Winform開發(fā)窗體

2021-07-06 14:32:54

機器學(xué)習(xí)人工智能計算機

2019-12-17 09:29:02

數(shù)據(jù)庫架構(gòu)分庫分表
點贊
收藏

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