Golang的strings.Split()坑怎么解决(golang,开发技术)

时间:2024-05-05 05:33:36 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    场景

    当时是需要取某个结构体的某个属性,并将其按,切分 整体逻辑类似这样的

    typeInfostruct{Idsstring//Ids:123,456}functest3(infoInfo){ids:=info.IdsidList:=strings.Split(ids,",")iflen(idList)<1{return}log.Println("ids-not-empty")//***}

    Golang的strings.Split()坑怎么解决

    ids = "" 时,控制台打印了 ids-not-empty ,当时百思不得其解,按理来说应该直接走return 这个问题激发了我的好奇心,决定认真排查一下

    前置

    在排查之前,先大概讲讲 Go 中string的基本结构

    golang的string它的运行时的数据结构位于reflect.StringHeader

    typestringHeaderstruct{Dataunsafe.PointerLenint}

    其中Data指向数据数组的指针 ,Len为数组的长度

    排查

    验证

    既然代码中的 if 判断为false,那么就实际打印一下 isList的长度看看呢

    functest3(infoInfo){ids:=info.IdsidList:=strings.Split(ids,",")log.Printf("idList长度:[%d],idList:[%v]",len(idList),idList)forindex,_:=rangeidList{log.Printf("idList[%d]:[%v]",index,idList[index])}//***}

    Golang的strings.Split()坑怎么解决

    打印底层信息

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

    const(basePrintInfoV3="%s字符串的指针地址:[%v],字符串buf数组地址:[%v],Len字段的地址:[%p],Len字段值:[%v]"basePrintInfoV2="%s切片的指针地址:[%p],切片数组地址:[%p],Len字段的地址:[%p],Len字段的值:[%v]")functest3(infoInfo){ids:=info.IdsidList:=strings.Split(ids,",")getStringPtr("ids",&ids)getStringSliceAllPtr("idList",&idList)//***}funcgetStringPtr(namestring,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)}funcgetStringSliceAllPtr(namestring,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)}

    Golang的strings.Split()坑怎么解决

    追源码

    ids 经过 split 之后的数组和预期的不一样,看来应该是 split 源码有特殊处理了,那追一下源码吧

    funcSplit(s,sepstring)[]string{returngenSplit(s,sep,0,-1)}

    大概读一遍源码能够理清楚genSplit思路

    • 预先确定s 能够被切分成n

    • 创建长度为n的数组

    • 遍历 s ,将每片数据放入数组中

    • 返回

    funcgenSplit(s,sepstring,sepSave,nint)[]string{ifn==0{returnnil}ifsep==""{returnexplode(s,n)}ifn<0{//计算s按照seq能被切成多少份n=Count(s,sep)+1}a:=make([]string,n)n--i:=0fori<n{//定位s里的第一个sep所在的位置m:=Index(s,sep)ifm<0{break}//放入返回的数组a[i]=s[:m+sepSave]//切割ss=s[m+len(sep):]i++}a[i]=sreturna[:i+1]}

    那么问题应该出就出在 Count 函数中

    跟进看看 count 函数会计算 s 字符串中包含了多少个 subStr

    funcCount(s,substrstring)int{//specialcaseiflen(substr)==0{returnutf8.RuneCountInString(s)+1}iflen(substr)==1{returnbytealg.CountString(s,substr[0])}n:=0for{i:=Index(s,substr)ifi==-1{returnn}n++s=s[i+len(substr):]}}

    Count 中会走 len(substr) == 1这个逻辑,其中的CountString计算s中存在多少个 substr[0],当时跟进,返回的结果是0 ,这里符合预期 。

    再结合 genSplit 中的 n = Count() + 1 我们可以发现,在genSplit时,预先创建的数组长度就为0 + 1 = 1 ! 问题迎刃而解

    类似情况

    经过查阅,这里再总结一下其他使用strings.Split可能遇到的坑

    s:=strings.Split("","")fmt.Println(s,len(s))//[]0//返回空数组s=strings.Split("abc,abc","")fmt.Println(s,len(s))//[abc,abc]7//返回7个数组元素s=strings.Split("",",")fmt.Println(s,len(s))//[]1s=strings.Split("abc,abc",",")fmt.Println(s,len(s))//[abcabc]2s=strings.Split("abc,abc","|")fmt.Println(s,len(s))//[abc,abc]1fmt.Println(len(""))//0fmt.Println(len([]string{""}))//1str:=""fmt.Println(str[0])//panic
     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:Golang的strings.Split()坑怎么解决的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:vue中el-autocomplete与el-select的异同点是什么下一篇:

    13 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18