精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試官:你能聊聊String和[]byte的轉換嗎?

開發 前端
為什么會有今天這篇文章呢?前天在一個群里看到了一份Go語言面試的八股文,其中有一道題就是"字符串轉成byte數組,會發生內存拷貝嗎?"

[[409227]]

本文轉載自微信公眾號「Golang夢工廠」,作者Golang夢工廠。轉載本文請聯系Golang夢工廠公眾號。

前言

哈嘍,大家好,我是asong。為什么會有今天這篇文章呢?前天在一個群里看到了一份Go語言面試的八股文,其中有一道題就是"字符串轉成byte數組,會發生內存拷貝嗎?";這道題挺有意思的,本質就是在問你string和[]byte的轉換原理,考驗你的基本功底。今天我們就來好好的探討一下兩者之間的轉換方式。

byte類型

我們看一下官方對byte的定義:

  1. // byte is an alias for uint8 and is equivalent to uint8 in all ways. It is 
  2. // used, by convention, to distinguish byte values from 8-bit unsigned 
  3. // integer values
  4. type byte = uint8 

我們可以看到byte就是uint8的別名,它是用來區分字節值和8位無符號整數值。

其實可以把byte當作一個ASCII碼的一個字符。

示例:

  1. var ch byte = 65 
  2. var ch byte = '\x41' 
  3. var ch byte = 'A' 

[]byte類型

[]byte就是一個byte類型的切片,切片本質也是一個結構體,定義如下:

  1. // src/runtime/slice.go 
  2. type slice struct { 
  3.     array unsafe.Pointer 
  4.     len   int 
  5.     cap   int 

這里簡單說明一下這幾個字段,array代表底層數組的指針,len代表切片長度,cap代表容量。看一個簡單示例:

  1. func main()  { 
  2.  sl := make([]byte,0,2) 
  3.  sl = append(sl, 'A'
  4.  sl = append(sl,'B'
  5.  fmt.Println(sl) 

根據這個例子我們可以畫一個圖:

string類型

先來看一下string的官方定義:

  1. // string is the set of all strings of 8-bit bytes, conventionally but not 
  2. // necessarily representing UTF-8-encoded text. A string may be empty, but 
  3. // not nil. Values of string type are immutable. 
  4. type string string 

string是一個8位字節的集合,通常但不一定代表UTF-8編碼的文本。string可以為空,但是不能為nil。string的值是不能改變的。

看一個簡單的例子:

  1. func main()  { 
  2.  str := "asong" 
  3.  fmt.Println(str) 

string類型本質也是一個結構體,定義如下:

  1. type stringStruct struct { 
  2.     str unsafe.Pointer 
  3.     len int 

stringStruct和slice還是很相似的,str指針指向的是某個數組的首地址,len代表的就是數組長度。怎么和slice這么相似,底層指向的也是數組,是什么數組呢?我們看看他在實例化時調用的方法:

  1. //go:nosplit 
  2. func gostringnocopy(str *byte) string { 
  3.  ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} 
  4.  s := *(*string)(unsafe.Pointer(&ss)) 
  5.  return s 

入參是一個byte類型的指針,從這我們可以看出string類型底層是一個byte類型的數組,所以我們可以畫出這樣一個圖片:

string和[]byte有什么區別

上面我們一起分析了string類型,其實他底層本質就是一個byte類型的數組,那么問題就來了,string類型為什么還要在數組的基礎上再進行一次封裝呢?

這是因為在Go語言中string類型被設計為不可變的,不僅是在Go語言,其他語言中string類型也是被設計為不可變的,這樣的好處就是:在并發場景下,我們可以在不加鎖的控制下,多次使用同一字符串,在保證高效共享的情況下而不用擔心安全問題。

string類型雖然是不能更改的,但是可以被替換,因為stringStruct中的str指針是可以改變的,只是指針指向的內容是不可以改變的。看個例子:

  1. func main()  { 
  2.  str := "song" 
  3.  fmt.Printf("%p\n",[]byte(str)) 
  4.  str = "asong" 
  5.  fmt.Printf("%p\n",[]byte(str)) 
  6. // 運行結果 
  7. 0xc00001a090 
  8. 0xc00001a098 

我們可以看出來,指針指向的位置發生了變化,也就說每一個更改字符串,就需要重新分配一次內存,之前分配的空間會被gc回收。

string和[]byte標準轉換

Go語言中提供了標準方式對string和[]byte進行轉換,先看一個例子:

  1. func main()  { 
  2.  str := "asong" 
  3.  by := []byte(str) 
  4.  
  5.  str1 := string(by
  6.  fmt.Println(str1) 

標準轉換用起來還是比較簡單的,那你知道他們內部是怎樣實現轉換的嗎?我們來分析一下:

  • string類型轉換到[]byte類型

我們對上面的代碼執行如下指令go tool compile -N -l -S ./string_to_byte/string.go,可以看到調用的是runtime.stringtoslicebyte:

  1. // runtime/string.go go 1.15.7 
  2. const tmpStringBufSize = 32 
  3.  
  4. type tmpBuf [tmpStringBufSize]byte 
  5.  
  6. func stringtoslicebyte(buf *tmpBuf, s string) []byte { 
  7.  var b []byte 
  8.  if buf != nil && len(s) <= len(buf) { 
  9.   *buf = tmpBuf{} 
  10.   b = buf[:len(s)] 
  11.  } else { 
  12.   b = rawbyteslice(len(s)) 
  13.  } 
  14.  copy(b, s) 
  15.  return b 
  16. // rawbyteslice allocates a new byte slice. The byte slice is not zeroed. 
  17. func rawbyteslice(size int) (b []byte) { 
  18.  cap := roundupsize(uintptr(size)) 
  19.  p := mallocgc(cap, nil, false
  20.  if cap != uintptr(size) { 
  21.   memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size)) 
  22.  } 
  23.  
  24.  *(*slice)(unsafe.Pointer(&b)) = slice{p, sizeint(cap)} 
  25.  return 

這里分了兩種狀況,通過字符串長度來決定是否需要重新分配一塊內存。也就是說預先定義了一個長度為32的數組,字符串的長度超過了這個數組的長度,就說明[]byte不夠用了,需要重新分配一塊內存了。這也算是一種優化吧,32是閾值,只有超過32才會進行內存分配。

最后我們會通過調用copy方法實現string到[]byte的拷貝,具體實現在src/runtime/slice.go中的slicestringcopy方法,這里就不貼這段代碼了,這段代碼的核心思路就是:將string的底層數組從頭部復制n個到[]byte對應的底層數組中去

  • []byte類型轉換到string類型

[]byte類型轉換到string類型本質調用的就是runtime.slicebytetostring:

  1. // 以下無關的代碼片段 
  2. func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) { 
  3.  if n == 0 { 
  4.   return "" 
  5.  } 
  6.  if n == 1 { 
  7.   p := unsafe.Pointer(&staticuint64s[*ptr]) 
  8.   if sys.BigEndian { 
  9.    p = add(p, 7) 
  10.   } 
  11.   stringStructOf(&str).str = p 
  12.   stringStructOf(&str).len = 1 
  13.   return 
  14.  } 
  15.  
  16.  var p unsafe.Pointer 
  17.  if buf != nil && n <= len(buf) { 
  18.   p = unsafe.Pointer(buf) 
  19.  } else { 
  20.   p = mallocgc(uintptr(n), nil, false
  21.  } 
  22.  stringStructOf(&str).str = p 
  23.  stringStructOf(&str).len = n 
  24.  memmove(p, unsafe.Pointer(ptr), uintptr(n)) 
  25.  return 

這段代碼我們可以看出會根據[]byte的長度來決定是否重新分配內存,最后通過memove可以拷貝數組到字符串。

string和[]byte強轉換

標準的轉換方法都會發生內存拷貝,所以為了減少內存拷貝和內存申請我們可以使用強轉換的方式對兩者進行轉換。在標準庫中有對這兩種方法實現:

  1. // runtime/string.go 
  2. func slicebytetostringtmp(ptr *byte, n int) (str string) { 
  3.  stringStructOf(&str).str = unsafe.Pointer(ptr) 
  4.  stringStructOf(&str).len = n 
  5.  return 
  6.  
  7. func stringtoslicebytetmp(s string) []byte { 
  8.     str := (*stringStruct)(unsafe.Pointer(&s)) 
  9.     ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len} 
  10.     return *(*[]byte)(unsafe.Pointer(&ret)) 

通過這兩個方法我們可知道,主要使用的就是unsafe.Pointer進行指針替換,為什么這樣可以呢?因為string和slice的結構字段是相似的:

  1. type stringStruct struct { 
  2.     str unsafe.Pointer 
  3.     len int 
  4. type slice struct { 
  5.     array unsafe.Pointer 
  6.     len   int 
  7.     cap   int 

唯一不同的就是cap字段,array和str是一致的,len是一致的,所以他們的內存布局上是對齊的,這樣我們就可以直接通過unsafe.Pointer進行指針替換。

兩種轉換如何取舍

當然是推薦大家使用標準轉換方式了,畢竟標準轉換方式是更安全的!但是如果你是在高性能場景下使用,是可以考慮使用強轉換的方式的,但是要注意強轉換的使用方式,他不是安全的,這里舉個例子:

  1. func stringtoslicebytetmp(s string) []byte { 
  2.  str := (*reflect.StringHeader)(unsafe.Pointer(&s)) 
  3.  ret := reflect.SliceHeader{Data: str.Data, Len: str.Len, Cap: str.Len} 
  4.  return *(*[]byte)(unsafe.Pointer(&ret)) 
  5.  
  6. func main()  { 
  7.  str := "hello" 
  8.  by := stringtoslicebytetmp(str) 
  9.  by[0] = 'H' 

運行結果:

  1. unexpected fault address 0x109d65f 
  2. fatal error: fault 
  3. [signal SIGBUS: bus error code=0x2 addr=0x109d65f pc=0x107eabc] 

我們可以看到程序直接發生嚴重錯誤了,即使使用defer+recover也無法捕獲。原因是什么呢?

我們前面介紹過,string類型是不能改變的,也就是底層數據是不能更改的,這里因為我們使用的是強轉換的方式,那么by指向了str的底層數組,現在對這個數組中的元素進行更改,就會出現這個問題,導致整個程序down掉!

總結

 

本文我們一起分析byte和string類型的基本定義,也分析了[]byte和string的兩種轉換方式,應該還差最后一環,也就是大家最關心的性能測試,這個我沒有做,我覺得沒有很大意義,通過前面的分析就可以得出結論,強轉換的方式性能肯定要比標準轉換要好。對于這兩種方式的使用,大家還是根據實際場景來選擇,脫離場景的談性能就是耍流氓!!!

 

責任編輯:武曉燕 來源: Golang夢工廠
相關推薦

2022-05-23 08:43:02

BigIntJavaScript內置對象

2023-08-11 17:13:39

JavaScrip

2024-07-25 18:20:03

2015-08-13 10:29:12

面試面試官

2025-07-25 01:45:00

RAG模型技術

2025-07-18 07:19:00

2022-10-08 00:08:00

apiESFacebook

2024-05-28 10:14:31

JavaScrip模板引擎

2019-04-29 14:59:41

Tomcat系統架構

2020-08-10 07:49:51

服務器

2024-01-22 10:07:48

Redis持久化功能緩存擊穿

2021-09-01 09:44:16

Redis持久化配置

2021-09-01 07:21:41

面試官開發讀寫鎖

2020-09-26 22:04:32

數據安全傳輸HTTPSHTTP 協議

2023-12-13 13:31:00

useEffect對象瀏覽器

2015-08-24 09:00:36

面試面試官

2021-11-25 10:18:42

RESTfulJava互聯網

2025-01-13 09:24:32

2021-08-09 07:47:40

Git面試版本

2021-12-27 06:57:40

This SuperJava
點贊
收藏

51CTO技術棧公眾號

污污污污污污www网站免费| 国产精品视频久久久久| 日本一区二区三区网站| 欧美舌奴丨vk视频| 国产精品久久国产精麻豆99网站| 综合激情国产一区| 狠狠干狠狠操视频| a级大胆欧美人体大胆666| 久久综合av免费| 成人网在线视频| 国产一级特黄aaa大片| 成人精品影视| 亚洲第一视频在线观看| 三级视频中文字幕| 136福利第一导航国产在线| 欧美国产一区二区在线观看| 亚洲japanese制服美女| av网站中文字幕| 国产精品v亚洲精品v日韩精品| 欧洲精品在线观看| 欧美大黑帍在线播放| 成人午夜电影在线观看| 丁香网亚洲国际| 国产日韩在线视频| 黄瓜视频在线免费观看| 欧美网站在线| 日韩中文字幕在线看| 鲁大师私人影院在线观看| 国产精品日本一区二区不卡视频| 国产精品三级av| 国产一区不卡在线观看| 一级片视频播放| 视频一区二区国产| 久久亚洲国产精品成人av秋霞| 少妇一级淫免费播放| 欧美freesex黑人又粗又大| 亚洲免费av网站| 亚洲午夜久久久影院伊人| 四季av日韩精品一区| 国产在线国偷精品免费看| 日本国产一区二区三区| 国产又色又爽又黄的| 国产综合婷婷| 久久影视电视剧免费网站清宫辞电视 | 亚洲综合丝袜美腿| 精品一区二区成人免费视频| 人人九九精品| 久久色.com| 麻豆精品视频| 国产资源在线播放| 国产亚洲综合在线| 日韩欧美一区二区视频在线播放| 国产精品女人久久久| 蜜臀av一区二区三区| 国产精品女视频| 中文字幕日产av| 日韩国产欧美在线观看| 国产成人精品日本亚洲专区61| 强制高潮抽搐sm调教高h| 欧美日韩第一| 综合网中文字幕| 俄罗斯毛片基地| 99久久夜色精品国产亚洲96| 久久久999精品免费| 午夜爽爽爽男女免费观看| 91精品观看| 欧美久久精品午夜青青大伊人| 国产网站无遮挡| 日韩av不卡一区| 日韩精品在线第一页| aaaaaav| 日本亚洲不卡| 亚洲人午夜精品免费| 一级在线观看视频| 我不卡伦不卡影院| 欧美极品美女电影一区| 欧美日韩综合在线观看| 久久精品三级| 成人免费在线网址| 亚洲爱爱综合网| 99re这里只有精品首页| 清纯唯美一区二区三区| 免费网站看v片在线a| 一区二区三区成人| 国产成人在线免费看| 欧美日一区二区三区| 7777精品伊人久久久大香线蕉完整版 | 亚洲黄页一区| 国产高清在线不卡| 国产精品久久久久久久成人午夜| 久久精品人人做人人爽电影蜜月| 久久久久久九九九| 天天干,天天干| 国产老女人精品毛片久久| 国产一区二区自拍| 三区四区在线视频| 亚洲图片欧美色图| 青青草av网站| 亚洲精品一区二区三区在线| 亚洲男人天堂2023| 特级片在线观看| 日本午夜一区二区| 国产一区二区三区高清| 亚乱亚乱亚洲乱妇| 精品欧美aⅴ在线网站| 日韩高清第一页| 中文字幕中文字幕精品| 美日韩精品免费观看视频| 久久中文字幕免费| 国产精品亚洲人在线观看| 日本不卡一区二区三区在线观看 | av免费观看国产| 日韩在线视频在线| 正在播放一区二区三区| 免费影视亚洲| 欧美日韩二区三区| 人妻精品久久久久中文字幕 | 91在线播放视频| 国产三级理论片| 成人精品国产一区二区4080| 亚洲精品久久区二区三区蜜桃臀| 国产视频二区在线观看| 亚洲毛片av在线| 亚洲免费看av| 久操成人av| 久久久伊人欧美| 国产熟女一区二区丰满| 中文字幕精品一区| 日韩av在线综合| 另类ts人妖一区二区三区| 欧美大片va欧美在线播放| 在线观看中文字幕2021| 久久久亚洲欧洲日产国码αv| 亚洲精品日韩成人| 欧美成人免费电影| 亚洲精品一区二区在线| 国产一级片免费| 国产精品99久久久久久久vr| 欧美日韩视频免费在线观看| 韩日一区二区| 中文字幕日韩专区| 久草热在线观看| 欧美—级在线免费片| 黄色a级片免费| 国产精品欧美三级在线观看| 欧美一级视频在线观看| 污视频网站在线播放| 性欧美大战久久久久久久久| 日本性生活一级片| 亚洲激情黄色| 就去色蜜桃综合| 伊人久久综合一区二区| 日韩一区二区三区在线观看| 女人又爽又黄免费女仆| 日韩主播视频在线| 深夜福利成人| 欧美视频在线视频精品| 久久精品电影网站| 国产夫妻自拍av| 亚洲v中文字幕| 蜜桃精品一区二区| 日本不卡一区二区| 中文字幕中文字幕在线中心一区 | 天天超碰亚洲| 亚洲最大福利视频网站| 青青在线视频| 日韩成人在线观看| 午夜精品免费观看| 国产农村妇女毛片精品久久麻豆 | 黑人另类av| 2020国产在线| 国产午夜一区二区| 国产麻豆免费视频| 亚洲一区二区在线观看视频 | 99热一区二区三区| 伊人久久大香线蕉av超碰| 欧美精品videos另类日本| 日本黄色大片视频| 色婷婷av一区二区三区大白胸| 18禁一区二区三区| 一本久道久久综合婷婷鲸鱼| 日本免费高清一区二区| 24小时成人在线视频| 欧美激情按摩在线| 欧美孕妇孕交xxⅹ孕妇交| 欧美日韩免费视频| 精品无码黑人又粗又大又长| 91日韩精品一区| 在线观看日本一区二区| 国产精品videosex极品| 欧美第一黄网| 日韩在线观看中文字幕| 日本电影亚洲天堂| av网站在线免费| 亚洲欧美日韩综合| 国产免费的av| 色婷婷综合久色| 黄色一级片在线免费观看| 久久综合九色综合97婷婷女人 | 青青草原综合久久大伊人精品优势| 国模精品一区二区三区| 向日葵视频成人app网址| 不卡中文字幕av| 巨骚激情综合| 精品国产亚洲在线| 一炮成瘾1v1高h| 日韩欧美aⅴ综合网站发布| 18岁成人毛片| 国产精品网曝门| 国产乱了高清露脸对白| 国产在线一区二区综合免费视频| 中文字幕成人一区| 免费欧美视频| 国产精品日韩一区二区三区| 激情亚洲小说| 国产盗摄xxxx视频xxx69| 888av在线视频| 播播国产欧美激情| 国产高清视频免费最新在线| 亚洲成人免费在线视频| 国产精品自偷自拍| 欧美系列亚洲系列| 一级片视频在线观看| 亚洲国产综合在线| 国产极品国产极品| 国产精品拍天天在线| 色欲av无码一区二区三区| 成人午夜激情影院| 国产探花一区二区三区| 九一九一国产精品| 狠狠操精品视频| 视频在线观看91| 日日摸日日碰夜夜爽av| 亚洲深夜福利| 噜噜噜久久亚洲精品国产品麻豆| 免费成人高清在线视频theav| 国产精品精品一区二区三区午夜版| 阿v免费在线观看| 亚洲美女精品成人在线视频| 五月婷婷丁香花| 亚洲国产日韩欧美在线99| 黄色www视频| 精品国偷自产国产一区| 蜜桃久久一区二区三区| 日韩三级中文字幕| 成 人 黄 色 片 在线播放| 欧美一区二区在线视频| 97人妻精品一区二区三区| 欧美日韩一卡二卡| 国产精品高潮呻吟久久久| 欧美三级视频在线观看| 黄色一区二区视频| 欧美日本在线播放| 国产日产亚洲系列最新| 欧美一卡二卡三卡| 亚洲精品97久久中文字幕| 精品久久久三级丝袜| 欧美自拍第一页| 日韩精品在线观看视频| 欧美日韩国产综合视频| 夜夜嗨av一区二区三区四区| yw193.com尤物在线| 色av吧综合网| 日韩特级毛片| 91av视频在线播放| free欧美| 成人h视频在线观看播放| 激情不卡一区二区三区视频在线 | 国产精品自拍第一页| 在线观看日韩电影| 国产精品高潮呻吟AV无码| 日韩精品在线一区| 日韩欧美电影在线观看| 一区二区国产精品视频| 欧美天天影院| 欧美黑人xxx| 韩国美女久久| 91免费欧美精品| 噜噜噜天天躁狠狠躁夜夜精品| 91精品天堂| 视频小说一区二区| 亚洲欧美一区二区原创| 国产精品videosex极品| 能在线观看的av| 精品一区二区综合| 亚洲欧美日韩偷拍| 国产精品欧美一区二区三区| 九九热精品在线观看| 色www精品视频在线观看| 国产日韩欧美中文字幕| 日韩精品欧美国产精品忘忧草 | 97超碰在线人人| 国产日韩1区| 亚洲天堂网2018| 99精品视频免费在线观看| 成人无码精品1区2区3区免费看 | 亚洲片在线观看| 久久bbxx| 欧美一级高清免费播放| 国产一区二区三区视频在线| 免费看国产精品一二区视频| 91精品国产91久久久久久密臀| 婷婷久久五月天| 亚洲看片一区| 污视频网址在线观看| 97精品久久久久中文字幕| 国产在线免费看| 一本色道久久综合狠狠躁的推荐| 四虎成人在线观看| 91精品国产色综合久久不卡电影| 国产又黄又爽视频| 亚洲欧美日本另类| 国产91足控脚交在线观看| 国产精品中文字幕在线| 国产99久久| 久久久国内精品| 精品一区二区影视| 一区二区精品免费| 午夜欧美视频在线观看| 国产剧情久久久| 日韩在线欧美在线| 欧美电影网址| 免费亚洲一区二区| 日韩一级精品| 手机在线成人av| 亚洲无线码一区二区三区| 国产精品久久久久久久成人午夜| 欧美精品一区二区三区在线播放 | av在线一区二区| 九九免费精品视频| 日韩精品一区二区三区四区视频| 刘亦菲毛片一区二区三区| www亚洲欧美| 黑人一区二区三区| 亚洲狠狠婷婷综合久久久| 亚洲男人影院| 亚洲精品视频大全| 精品久久久久久电影| 午夜黄色小视频| 欧美亚洲在线观看| 人人香蕉久久| 女性隐私黄www网站视频| 99精品视频一区二区三区| 91视频免费网址| 亚洲欧美日韩精品久久奇米色影视 | 51一区二区三区| 婷婷久久伊人| 久久99国产精品久久99果冻传媒| 又大又长粗又爽又黄少妇视频| 91丝袜美腿高跟国产极品老师 | 制服下的诱惑暮生| 亚洲丝袜另类动漫二区| 亚洲视频久久久| 精品国产一区二区三区久久久狼| 性欧美18~19sex高清播放| 精品国产乱码久久久久软件 | ccyy激情综合| 国内精品视频一区二区三区| 国产精品主播直播| 精品一区二区三区人妻| 亚洲国产精品成人一区二区| 狠狠操一区二区三区| 日本一区免费| 久久超碰97中文字幕| www.毛片com| 亚洲а∨天堂久久精品喷水| 人在线成免费视频| 日韩一区二区三区高清| 久久99国产精品尤物| 久久久久久久久久综合| 日韩精品电影网| 巨胸喷奶水www久久久免费动漫| 国产精品免费在线| 欧美日本一区二区视频在线观看| 国产精品视频黄色| 亚洲欧洲日本在线| 性生活视频软件| 国产v综合v亚洲欧美久久| 色乱码一区二区三区网站| 国产吃瓜黑料一区二区| 日韩欧美亚洲综合| 毛片免费不卡| 精品无人区一区二区三区| 日韩成人一区二区| 久久久久久国产精品视频| 精品中文字幕久久久久久| 亚洲18在线| 69堂免费视频| 亚洲欧美视频在线观看视频| 亚洲欧美日韩综合在线| 91精品视频在线播放| 国产精品久久国产愉拍| 亚洲一区电影在线观看| 国产丝袜一区二区三区免费视频| 国产h片在线观看| 亚洲精品影院| 高清视频一区二区| 亚洲一线在线观看| 91精品国产高清久久久久久久久| 少妇久久久久|