Golang源码阅读笔记 - String
String用法说明
在src/buildin/buildin.go
文件中,对golang内建数据类型做了详细的描述,关于string
的说明如下:
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string
- 从中我们可以获取以下信息:
- 字符串是8比特字节的集合
- 字符串一般但不一定是
UTF-8
文本- 个人理解,golang默认是使用
UTF-8
编码的,但是支持用户修改编码方式
- 个人理解,golang默认是使用
- 字符串可以为空
""
,但不能为nil
- 字符串不可修改
string底层数据结构
type stringStruct struct {str unsafe.Pointerlen int
}
- String底层由两个字段组成
str unsafe.Pointer
: 指向底层数组的指针len int
: 字符串长度
- 由底层数据结构可知,
len(string)
的时间复杂度是O(1)
基础函数
hasPrefix(s, prefix string)
: 字符串s
是否有前缀字符串prefix
,时间复杂度O(1)func hasPrefix(s, prefix string) bool {return len(s) >= len(prefix) && s[:len(prefix)] == prefix // 这个 == 的原理是什么??? }
index(s, t string)
: 判断字符串t
在字符串s
中首次初选的位置,时间复杂度O(n)func index(s, t string) int {if len(t) == 0 {return 0}for i := 0; i < len(s); i++ {if s[i] == t[0] && hasPrefix(s[i:], t) {return i}}return -1 }
contains(s, t string) bool
: 字符串s
是否包含字符串t
, 即通过index查看首次出现的位置时间复杂度O(n)func contains(s, t string) bool {return index(s, t) >= 0 }
stringStructOf(sp *string) *stringStruct
: 获取字符串sp
的底层数据结构体stringStruct
func stringStructOf(sp *string) *stringStruct {return (*stringStruct)(unsafe.Pointer(sp)) }
rawstring(size int) (s string, b []byte)
: 获取字节大小为size的字符串// rawstring allocates storage for a new string. The returned // string and byte slice both refer to the same storage. // The storage is not zeroed. func rawstring(size int) (s string, b []byte) {p := mallocgc(uintptr(size), nil, false) // 先分配一段内存空间,大小为size个字节,无类型,无零值stringStructOf(&s).str = p // 将分配内存空间的地址,赋值给string的底层slice指针stringStructOf(&s).len = size // 字符串s大小为size个字节*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size} // 同时,定义一个slice类型(也指向同一个地址空间)赋值给breturn }
rawstring
函数给一个新字符串分配存储,返回一个字符串和一个字节slice,两者指向同一个内存空间,存储空间没有初始化零值(mallocgc函数未初始化零值)stringDataOnStack(s string)
: 字符串s是否在当前goroutine的栈上func stringDataOnStack(s string) bool {ptr := uintptr(stringStructOf(&s).str) // 获取字符串s的指针地址stk := getg().stack // 获取当前goroutine的栈指针return stk.lo <= ptr && ptr < stk.hi // 字符串s的地址是否在栈的高低地址之间 }
slicebytetostringtmp
: 把字节slice转换成字符串。其实就是把字节slice的指针赋值给字符串s的地址指针,再加上长度n即可func slicebytetostringtmp(ptr *byte, n int) (str string) {stringStructOf(&str).str = unsafe.Pointer(ptr)stringStructOf(&str).len = nreturn }
string拼接x + y + z
func concatstrings(buf *tmpBuf, a []string) string {idx := 0l := 0count := 0for i, x := range a {n := len(x)if n == 0 {continue}if l+n < l {throw("string concatenation too long")}l += ncount++idx = i}if count == 0 {return ""}if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {return a[idx]}s, b := rawstringtmp(buf, l)for _, x := range a {copy(b, x)b = b[len(x):]}return s
}
多个字符串拼接,其原理是先遍历所有子字符串,获取其长度l后,先在内存中分配长度l的内存空间,然后将子字符串依次赋值到新空间内。时间复杂度为O(n)
string转slice
// 定义了默认缓冲区大小为32bytes
const tmpStringBufSize = 32
type tmpBuf [tmpStringBufSize]byte// string => Slice
func stringtoslicebyte(buf *tmpBuf, s string) []byte {var b []byte// 如果字符串长度小于32bytes,直接使用默认缓冲区if buf != nil && len(s) <= len(buf) {*buf = tmpBuf{}b = buf[:len(s)]} else {// 如果字符换长度大于32bytes,需要新申请一块内存区域b = rawbyteslice(len(s))}// 始终产生一次数据拷贝copy(b, s)return b
}// 重新申请一块内存,构建新的byte slice
func rawbyteslice(size int) (b []byte) {cap := roundupsize(uintptr(size))p := mallocgc(cap, nil, false)if cap != uintptr(size) {memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))}*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}return
}
slice转string
func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {...var p unsafe.Pointer// 如果字节数小于32,直接使用缓冲区if buf != nil && n <= len(buf) {p = unsafe.Pointer(buf)} else {// 否则,重新申请内存p = mallocgc(uintptr(n), nil, false)}// 构建string,内存为tmp地址或新申请内存地址,长度为nstringStructOf(&str).str = pstringStructOf(&str).len = n// 从ptr指针拷贝n个字节到p指针,也存在一次数据拷贝memmove(p, unsafe.Pointer(ptr), uintptr(n))return
}
Golang源码阅读笔记 - String相关推荐
- syzkaller 源码阅读笔记1(syz-extract syz-sysgen)
文章目录 1. syz-extract 1-0 总结 1-1. `main()` 1-2 `archList()` - `1-1 (3)` 获取架构 name list 1-3 `createArch ...
- 代码分析:NASM源码阅读笔记
NASM源码阅读笔记 NASM(Netwide Assembler)的使用文档和代码间的注释相当齐全,这给阅读源码 提供了很大的方便.按作者的说法,这是一个模块化的,可重用的x86汇编器, 而且能够被 ...
- Yii源码阅读笔记 - 日志组件
2015-03-09 一 By youngsterxyf 使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category); Yii: ...
- 【Flink】Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型
1.概述 转载:Flink 源码阅读笔记(20)- Flink 基于 Mailbox 的线程模型 相似文章:[Flink]Flink 基于 MailBox 实现的 StreamTask 线程模型 Fl ...
- 【Flink】Flink 源码阅读笔记(15)- Flink SQL 整体执行框架
1.概述 转载:Flink 源码阅读笔记(15)- Flink SQL 整体执行框架 在数据处理领域,无论是实时数据处理还是离线数据处理,使用 SQL 简化开发将会是未来的整体发展趋势.尽管 SQL ...
- Android TV TIF源码阅读笔记
Android TV TIF源码阅读笔记 1.SystemSever.java if (mPackageManager.hasSystem ...
- go源码阅读笔记(unsafe)
go源码阅读笔记(unsafe) unsafe 包主要是可以使得用户绕过go的类型规范检查,能够对指针以及其指向的区域进行读写操作. package mathimport "unsafe&q ...
- svf源码阅读笔记(一)
svf源码阅读笔记(一) SVF/tools/Example/svf-ex.cpp 驱动程序 int main(int argc, char ** argv) {int arg_num = 0;cha ...
- Transformers包tokenizer.encode()方法源码阅读笔记
Transformers包tokenizer.encode()方法源码阅读笔记_天才小呵呵的博客-CSDN博客_tokenizer.encode
最新文章
- wubantu18.04版,pycharm2.18.3.2永久破解来了,借鉴个位大神的教程破掉的,感谢各位大佬...
- xbox acc驱动win7_Xbox老大:希望第一方工作室能推出更多单机游戏_电竞
- BUUCTF 特殊的BASE64
- 查询Oracle正在执行的sql语句,锁表,解锁
- python sqlite
- 阿里云专有网络环境下不同账号之间内网互通(内网高速通道)
- VirusTotal 共享8000万勒索软件样本分析数据库
- MySQL优化详解(四)——MySQL缓存设置
- C语言题目:5-7 购物(二) (25 分)
- 用selenium实现百度贴吧自动发帖
- iMazing怎么恢复备份?iMazing恢复备份教程分享
- 程序员日常工作总结2020-01-21
- PHP获取客户端真实 IP 地址
- 关于HTML的一些知识
- python中的特殊用法
- C4D R25调节网格间距的方法
- 数字后端基本概念介绍Tie cell
- 深入探索C语言struct的用法
- ALBRECHT密钻夹头SK30 2-14mm A92
- 安卓碎片(Fragment)的使用
热门文章
- C语言之scanf超详细解析
- 小学计算机六年级下教学计划,人教版小学六年级下册信息技术教学计划范文(通用3篇)...
- ZIP压缩包设置密码和删除密码
- JAVA swing实现简单的学生管理系统
- InvalidateRect()与Invalidate()的用法(转)
- 判断素数———两种高效算法
- pytorch深度学习入门与实战——今天我们来对一张图像进行卷积、池化,以及激活层的使用展示
- 十年风雨,一个普通程序员的成长之路(一)怀念:西安的小黑屋
- 和尚啃源码 之 RM深大开源RP_Infantry_Plus
- 人员管理KPI和OKR