Go语言核心36讲
郝林
《Go并发编程实战》作者,前轻松筹大数据负责人
立即订阅
24094 人已学习
课程目录
已完结 54 讲
0/4登录后,你可以任选4讲全文学习。
开篇词+学习路线 (3讲)
开篇词 | 跟着学,你也能成为Go语言高手
免费
预习篇 | 写给0基础入门的Go语言学习者
50 | 学习专栏的正确姿势
模块一:Go语言基础知识 (6讲)
01 | 工作区和GOPATH
02 | 命令源码文件
03 | 库源码文件
04 | 程序实体的那些事儿(上)
05 | 程序实体的那些事儿(中)
06 | 程序实体的那些事儿 (下)
模块二:Go语言进阶技术 (16讲)
07 | 数组和切片
08 | container包中的那些容器
09 | 字典的操作和约束
10 | 通道的基本操作
11 | 通道的高级玩法
12 | 使用函数的正确姿势
13 | 结构体及其方法的使用法门
14 | 接口类型的合理运用
15 | 关于指针的有限操作
16 | go语句及其执行规则(上)
17 | go语句及其执行规则(下)
18 | if语句、for语句和switch语句
19 | 错误处理(上)
20 | 错误处理 (下)
21 | panic函数、recover函数以及defer语句 (上)
22 | panic函数、recover函数以及defer语句(下)
模块三:Go语言实战与应用 (27讲)
23 | 测试的基本规则和流程 (上)
24 | 测试的基本规则和流程(下)
25 | 更多的测试手法
26 | sync.Mutex与sync.RWMutex
27 | 条件变量sync.Cond (上)
28 | 条件变量sync.Cond (下)
29 | 原子操作(上)
30 | 原子操作(下)
31 | sync.WaitGroup和sync.Once
32 | context.Context类型
33 | 临时对象池sync.Pool
34 | 并发安全字典sync.Map (上)
35 | 并发安全字典sync.Map (下)
36 | unicode与字符编码
37 | strings包与字符串操作
38 | bytes包与字节串操作(上)
39 | bytes包与字节串操作(下)
40 | io包中的接口和工具 (上)
41 | io包中的接口和工具 (下)
42 | bufio包中的数据类型 (上)
43 | bufio包中的数据类型(下)
44 | 使用os包中的API (上)
45 | 使用os包中的API (下)
46 | 访问网络服务
47 | 基于HTTP协议的网络服务
48 | 程序性能分析基础(上)
49 | 程序性能分析基础(下)
尾声与思考题答案 (2讲)
尾声 | 愿你披荆斩棘,所向无敌
新年彩蛋 | 完整版思考题答案
Go语言核心36讲
登录|注册

37 | strings包与字符串操作

郝林 2018-11-05
在上一篇文章中,我介绍了 Go 语言与 Unicode 编码规范、UTF-8 编码格式的渊源及运用。
Go 语言不但拥有可以独立代表 Unicode 字符的类型rune,而且还有可以对字符串值进行 Unicode 字符拆分的for语句。
除此之外,标准库中的unicode包及其子包还提供了很多的函数和数据类型,可以帮助我们解析各种内容中的 Unicode 字符。
这些程序实体都很好用,也都很简单明了,而且有效地隐藏了 Unicode 编码规范中的一些复杂的细节。我就不在这里对它们进行专门的讲解了。
我们今天主要来说一说标准库中的strings代码包。这个代码包也用到了不少unicode包和unicode/utf8包中的程序实体。
比如,strings.Builder类型的WriteRune方法。
又比如,strings.Reader类型的ReadRune方法,等等。
下面这个问题就是针对strings.Builder类型的。我们今天的问题是:与string值相比,strings.Builder类型的值有哪些优势?
这里的典型回答是这样的。
strings.Builder类型的值(以下简称Builder值)的优势有下面的三种:
已存在的内容不可变,但可以拼接更多的内容;
减少了内存分配和内容拷贝的次数;
可将内容重置,可重用值。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Go语言核心36讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(10)

  • Realm
    1 string拼接的结果是生成新的string,需要把原字符串拷贝到新的string中;Builder底层有个[]byte,按需扩容,不必每次拼接都需要拷贝;

    2 Reader的优势是维护一个已读计数器,知道下一次读的位置,读得更快.

    作者回复: 嗯,是的。

    2018-11-05
    12
  • 虢国技匠
    二刷了一遍,又看了一遍源码;我觉得对于Builder和Reader理解应该注意:
    1,结构:
        1.1 Builder结构体内部内容容器是一个切片buf还有一个addr(复制检测用的指针)
        1.2 Reader结构体内部内容容器是一个string的s和一个内部计数器i
    2. Builder
        2.1 想法方法内部先调用copyCheck方法进行值复制的检测(即老师说的使用后在复制引发panic就是这个方法)
        2.2 内容容器是切片,相关拼接方法内部应用的是append函数,这些方法使用时间可以结合slice和append的原理
        2.3 公开方法Grow进行是否扩容判断逻辑,然后调用内部方法grow执行切片扩容,扩容策略:原内容容器切片容量 * 2 + Grow参数n;用这个容量make申请新的内存空间,然后copy原内容容器切片底层数组值

    3. Reader
       3.1 读取方法底层是对内容容器s字符串的切片操作,这里要注意在多字节字符读取时,字符串的切片操作可能会导致拿到的字符串有乱码的风险,
       3.2 对于Read、ReadAt这些将字符串读取到传入的切片参数时,底层应用的是copy函数,so最终读出的字符串字节切片长度是copy函数两个参数中较小的一个参数的长度。同时Read、ReadAt这些方法的off参数不恰当时,会因为多字节字符串切片导致两头可能出现乱码
    2019-12-09
    1
  • jimmy
    strings.Builder里边的String方法是
    // String returns the accumulated string.
    func (b *Builder) String() string {
    return *(*string)(unsafe.Pointer(&b.buf))
    }
    这样实现的, 请问老师为什么不是
    // String returns the accumulated string.
    func (b *Builder) String() string {
    return string(b.buf)
    }
    有什么特殊的点吗? 谢谢

    作者回复: 省去了类型转换的开销,效率会高很多。

    2019-01-17
    1
  • 南方有嘉木
    请问容量增加n个字节,为什么是原来的2倍再加上n呢
    2018-11-27
    1
  • Cloud
    很实用!
    2018-11-05
    1
  • 博博
    Builder类型中的addr *Builder 字段的意义是什么呢?

    作者回复: 这个 addr 字段的意义是,保存其所属值所在的内存地址。如此一来,一旦这个值被拷贝了,使用内存地址比较的方式就可以检测出来。

    2019-05-22
  • Garry
    老师,我在看strings 源码的时候发现了
    func noescape(p unsafe.Pointer) unsafe.Pointer {
    x := uintptr(p)
    return unsafe.Pointer(x ^ 0)
    }
    这个函数 最后用了个x ^ 0,但是这么操作的最后结果不还是x么,为何还要这样操作呢

    作者回复: 为了产生一个新值啊,要跟这个函数的参数值划清界限。

    2019-04-02
  • Geek_1ed70f
    读源代码讲得好深....
    2019-03-14
  • 虢国技匠
    打卡
    2019-03-04
  • kingkang
    请问byte数组转string出现乱码怎么处理?

    作者回复: 如果字节数组的内容不是UTF-8编码的Unicode字符,这样直接转就会出现乱码。先要搞清楚两个问题:1. 这个字节数组的内容会是可打印的字符吗?2. 如果是可打印的字符,那它使用什么编码的?

    2019-01-04
收起评论
10
返回
顶部