golang的string类型底层数据结构简单,本质也是一个结构体实例,且是const不可变。

string的底层数据结构

通过下面一个例子来看:

string的拼接与修改

+操作

string类型是一个不可变类型,那么任何对string的修改都会新生成一个string的实例,如果是考虑效率的场景就要好好考虑一下如何修改了。先说一下最长用的+操作,同样上面的例子,看一下+操作拼接字符串的反汇编:

因为当前go[2018.11 version: go1.11]的不是遵循默认的x86 calling convention用寄存器传参,而是通过stack进行传参,所以go的反汇编不像c的那么容易理解,不过大概看懂+背后的操作还是没问题的,看一下runtime源码的拼接函数:

分析runtime的concatstrings实现,可以看出+最后新申请buf,拷贝原来的string到buf,最后返回新实例。那么每次的+操作,都会涉及新申请buf,然后是对应的copy。如果反复使用+,就不可避免有大量的申请内存操作,对于大量的拼接,性能就会受到影响了。

bytes.buffer

通过看源码,bytes.buffer 增长buffer时是按照2倍来增长内存,可以有效避免频繁的申请内存,通过一个例子来看:

对应的byte包库函数源码

string.join

这个函数可以一次申请最终string的大小,但是使用得预先准备好所有string,这种场景也是高效的,一个例子:

对应库的源码:

strings.builder (go1.10+)

看到这个名字,就想到了java的库,哈哈,这个builder用起来是最方便的,不过是在1.10后引入的。其高效也是体现在2倍速的内存增长, writestring函数利用了slice类型对应append函数的2倍速增长。

一个例子:

对应库的源码

总结

golang的字符串处理还是挺方便的,有垃圾回收和一些内置的语言级写法支持,让复杂字符串操作没有那么繁琐了,比起c/c++高效了不少。

补充:go string的内部实现

go string 内部实现

这个string的探索

来来个例子

其中

其实可以看到string就是c里面的char* 和len的组合

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。如有错误或未考虑完全的地方,望不吝赐教。