最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang的strings.Split()踩坑記錄

 更新時(shí)間:2022年05月29日 11:15:47   作者:酒紅  
工作中,當(dāng)我們需要對(duì)字符串按照某個(gè)字符串切分成字符串?dāng)?shù)組數(shù)時(shí),常用到strings.Split(),本文主要介紹了Golang的strings.Split()踩坑記錄,感興趣的可以了解一下

背景

工作中,當(dāng)我們需要對(duì)字符串按照某個(gè)字符串切分成字符串?dāng)?shù)組數(shù)時(shí),常用到strings.Split()

最近在使用過(guò)程中踩到了個(gè)坑,后對(duì)踩坑原因做了分析,并總結(jié)了使用string.Split可能踩到的坑。最后寫(xiě)本篇文章做復(fù)盤(pán)總結(jié)與分享

場(chǎng)景

當(dāng)時(shí)是需要取某個(gè)結(jié)構(gòu)體的某個(gè)屬性,并將其按,切分 整體邏輯類(lèi)似這樣的

type Info struct{
   Ids string // Ids: 123,456
}

func test3(info Info){
   ids := info.Ids
   idList := strings.Split(ids , ",")
   if len(idList) < 1 {
      return
   }
   log.Println("ids-not-empty")
   // ***
}

當(dāng)ids = "" 時(shí),控制臺(tái)打印了 ids-not-empty ,當(dāng)時(shí)百思不得其解,按理來(lái)說(shuō)應(yīng)該直接走return 這個(gè)問(wèn)題激發(fā)了我的好奇心,決定認(rèn)真排查一下

前置

在排查之前,先大概講講 Go 中string的基本結(jié)構(gòu)

golang的string它的運(yùn)行時(shí)的數(shù)據(jù)結(jié)構(gòu)位于reflect.StringHeader

type stringHeader struct {
   Data unsafe.Pointer
   Len  int
}

其中Data指向數(shù)據(jù)數(shù)組的指針 ,Len為數(shù)組的長(zhǎng)度

排查

驗(yàn)證

既然代碼中的 if 判斷為false,那么就實(shí)際打印一下 isList的長(zhǎng)度看看呢

func test3(info Info){  
    ids := info.Ids
    idList := strings.Split(ids, ",")
    log.Printf("idList長(zhǎng)度: [%d], idList: [%v]", len(idList), idList)
    for index, _ := range idList {
       log.Printf("idList[%d]:[%v]", index, idList[index])
    }    
   // ***
}

打印底層信息

好奇心加深,打印一下idsidList的信息

const (
  basePrintInfoV3 = "%s 字符串的指針地址:[%v],字符串buf數(shù)組地址:[%v] ,Len字段的地址:[%p] ,Len字段值:[%v]"
  basePrintInfoV2 = "%s切片的指針地址:[%p],切片數(shù)組地址:[%p], Len字段的地址:[%p], Len字段的值:[%v]"
)

func test3(info Info) {
  ids := info.Ids
  idList := strings.Split(ids, ",")
  getStringPtr("ids ", &ids)
  getStringSliceAllPtr("idList ", &idList)
  // ***
}
func getStringPtr(name string, str *string) {
   s2 := (*reflect.StringHeader)(unsafe.Pointer(str))
   log.Printf(basePrintInfoV3, name, unsafe.Pointer(str), unsafe.Pointer(s2.Data), unsafe.Pointer(&s2.Len), s2.Len)
}

func getStringSliceAllPtr(name string, s1 *[]string) {
   s2 := (*reflect.StringHeader)(unsafe.Pointer(s1))
   log.Printf(basePrintInfoV2, name, unsafe.Pointer(&s1), unsafe.Pointer(s2.Data), unsafe.Pointer(&s2.Len), s2.Len)
}

追源碼

ids 經(jīng)過(guò) split 之后的數(shù)組和預(yù)期的不一樣,看來(lái)應(yīng)該是 split 源碼有特殊處理了,那追一下源碼吧

func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }

大概讀一遍源碼能夠理清楚genSplit思路

  • 預(yù)先確定s 能夠被切分成n
  • 創(chuàng)建長(zhǎng)度為n的數(shù)組
  • 遍歷 s ,將每片數(shù)據(jù)放入數(shù)組中
  • 返回
func genSplit(s, sep string, sepSave, n int) []string {
   if n == 0 {
      return nil
   }
   if sep == "" {
      return explode(s, n)
   }
   if n < 0 {
      // 計(jì)算 s 按照 seq 能被切成多少份
      n = Count(s, sep) + 1
   }

   a := make([]string, n)
   n--
   i := 0
   for i < n {
      // 定位 s里的第一個(gè) sep 所在的位置
      m := Index(s, sep)
      if m < 0 {
         break
      }
      // 放入返回的數(shù)組
      a[i] = s[:m+sepSave]
      // 切割s
      s = s[m+len(sep):]
      i++
   }
   a[i] = s
   return a[:i+1]
}

那么問(wèn)題應(yīng)該出就出在 Count 函數(shù)中

跟進(jìn)看看 count 函數(shù)會(huì)計(jì)算 s 字符串中包含了多少個(gè) subStr

func Count(s, substr string) int {
   // special case
   if len(substr) == 0 {
      return utf8.RuneCountInString(s) + 1
   }
   if len(substr) == 1 {
      return bytealg.CountString(s, substr[0])
   }
   n := 0
   for {
      i := Index(s, substr)
      if i == -1 {
         return n
      }
      n++
      s = s[i+len(substr):]
   }
}

Count 中會(huì)走 len(substr) == 1這個(gè)邏輯,其中的CountString計(jì)算s中存在多少個(gè) substr[0],當(dāng)時(shí)跟進(jìn),返回的結(jié)果是0 ,這里符合預(yù)期 。

再結(jié)合 genSplit 中的 n = Count() + 1 我們可以發(fā)現(xiàn),在genSplit時(shí),預(yù)先創(chuàng)建的數(shù)組長(zhǎng)度就為0 + 1 = 1 ! 問(wèn)題迎刃而解

類(lèi)似情況

經(jīng)過(guò)查閱,這里再總結(jié)一下其他使用strings.Split可能遇到的坑

s := strings.Split("", "")
fmt.Println(s, len(s)) // [] 0 //返回空數(shù)組

s = strings.Split("abc,abc", "")
fmt.Println(s, len(s)) // [a b c , a b c] 7 //返回7個(gè)數(shù)組元素

s = strings.Split("", ",")
fmt.Println(s, len(s)) // [] 1 

s = strings.Split("abc,abc", ",")
fmt.Println(s, len(s)) // [abc abc] 2

s = strings.Split("abc,abc", "|")
fmt.Println(s, len(s)) // [abc,abc] 1

fmt.Println(len("")) // 0
fmt.Println(len([]string{""})) // 1 

str := ""
fmt.Println(str[0]) // panic

總結(jié)

這次小小的踩坑其實(shí)也算是繞了一點(diǎn)點(diǎn)彎路,直接讀源碼就好了 hhhhhh

到此這篇關(guān)于Golang的strings.Split()踩坑記錄的文章就介紹到這了,更多相關(guān)Golang strings.Split()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Go Validator有效驗(yàn)證數(shù)據(jù)示例分析

    使用Go Validator有效驗(yàn)證數(shù)據(jù)示例分析

    作為一名開(kāi)發(fā)者,確保Go應(yīng)用中處理的數(shù)據(jù)是有效和準(zhǔn)確的非常重要,Go Validator是一個(gè)開(kāi)源的數(shù)據(jù)驗(yàn)證庫(kù),為Go結(jié)構(gòu)體提供強(qiáng)大且易于使用的數(shù)據(jù)驗(yàn)證功能,本篇文章將介紹Go Validator庫(kù)的主要特點(diǎn)以及如何在Go應(yīng)用中使用它來(lái)有效驗(yàn)證數(shù)據(jù)
    2023-12-12
  • Golang搭建grpc環(huán)境的流程步驟

    Golang搭建grpc環(huán)境的流程步驟

    這篇文章主要給大家介紹了Golang搭建grpc環(huán)境的流程步驟,文中通過(guò)圖文結(jié)合的方式給大家講解的非常詳細(xì),對(duì)大家了解Golang搭建grpc環(huán)境有一定的幫助,需要的朋友可以參考下
    2024-03-03
  • 淺析Go項(xiàng)目中的依賴(lài)包管理與Go?Module常規(guī)操作

    淺析Go項(xiàng)目中的依賴(lài)包管理與Go?Module常規(guī)操作

    這篇文章主要為大家詳細(xì)介紹了Go項(xiàng)目中的依賴(lài)包管理與Go?Module常規(guī)操作,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Golang?中的?strconv?包常用函數(shù)及用法詳解

    Golang?中的?strconv?包常用函數(shù)及用法詳解

    strconv是Golang中一個(gè)非常常用的包,主要用于字符串和基本數(shù)據(jù)類(lèi)型之間的相互轉(zhuǎn)換,這篇文章主要介紹了Golang中的strconv包,需要的朋友可以參考下
    2023-06-06
  • Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能對(duì)比場(chǎng)景分析

    Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能對(duì)比場(chǎng)景分析

    這篇文章主要介紹了Go標(biāo)準(zhǔn)庫(kù)http與fasthttp服務(wù)端性能比較,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • 實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE) 簡(jiǎn)介附go實(shí)現(xiàn)示例代碼

    實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE) 簡(jiǎn)介附go實(shí)現(xiàn)示例代碼

    EventSource是一種非常有用的 API,適用于許多實(shí)時(shí)應(yīng)用場(chǎng)景,它提供了一種簡(jiǎn)單而可靠的方式來(lái)建立服務(wù)器推送連接,并實(shí)現(xiàn)實(shí)時(shí)更新和通知,這篇文章主要介紹了實(shí)時(shí)通信的服務(wù)器推送機(jī)制 EventSource(SSE)簡(jiǎn)介附go實(shí)現(xiàn)示例,需要的朋友可以參考下
    2024-03-03
  • 詳解Go語(yǔ)言微服務(wù)開(kāi)發(fā)框架之Go chassis

    詳解Go語(yǔ)言微服務(wù)開(kāi)發(fā)框架之Go chassis

    分布式系統(tǒng)中每個(gè)進(jìn)程的動(dòng)態(tài)配置管理及運(yùn)行時(shí)熱加載就成為了一個(gè)亟待解決的問(wèn)題。go chassis汲取了netflix的archaius框架經(jīng)驗(yàn),并做出來(lái)自己的創(chuàng)新特性。
    2021-05-05
  • GoFrame?gredis緩存DoVar及Conn連接對(duì)象的自動(dòng)序列化

    GoFrame?gredis緩存DoVar及Conn連接對(duì)象的自動(dòng)序列化

    這篇文章主要為大家介紹了GoFrame?gredis干貨DoVar?Conn連接對(duì)象自動(dòng)序列化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go語(yǔ)言題解LeetCode888公平糖果交換示例詳解

    Go語(yǔ)言題解LeetCode888公平糖果交換示例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言題解LeetCode888公平糖果交換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • go編譯標(biāo)簽build?tag注釋里語(yǔ)法詳解

    go編譯標(biāo)簽build?tag注釋里語(yǔ)法詳解

    這篇文章主要為大家介紹了go編譯標(biāo)簽build?tag注釋里語(yǔ)法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09

最新評(píng)論

清远市| 巴东县| 施秉县| 阳朔县| 遂溪县| 九龙坡区| 奉贤区| 桑植县| 贺兰县| 桦川县| 利辛县| 曲沃县| 淮北市| 曲沃县| 开鲁县| 息烽县| 大名县| 南宁市| 磐石市| 镇远县| 深州市| 安福县| 石景山区| 元江| 红安县| 宜良县| 宝应县| 芜湖市| 洪湖市| 禹城市| 韶山市| 镇雄县| 洪江市| 濮阳县| 吉隆县| 正安县| 苏州市| 桓仁| 江华| 孝感市| 衢州市|