首页 > 其他分享 >Go语言精进之路读书笔记第15条——了解string实现原理并高效使用

Go语言精进之路读书笔记第15条——了解string实现原理并高效使用

时间:2024-02-07 17:45:51浏览次数:36  
标签:int32 15 string 读书笔记 fmt 字符串 rune Go

15.1 Go语言的字符串类型

在Go语言中,无论是字符串常量、字符串变量还是代码中出现的字符串字面量,它们的类型都被统一设置为string

特点

  1. string类型的数据是不可变的
    • 对string进行切片化后,Go编译器会为切片变量重新分配底层存储而不是共用string的底层存储
    • string的底层的数据存储区仅能进行只读操作,一旦试图修改那块区域的数据,便会得到SIGBUS的运行时错误
  2. 零值可用
  3. 获取长度的时间复杂度是O(1)级别
  4. 支持通过+/+=操作符进行字符串连接
  5. 支持各种比较关系操作符:==、!= 、>=、<=、>和<
  6. 对非ASCII字符提供原生支持
  7. 原生支持多行字符串(使用 ``)
  8. 直接将string类型通过函数/方法参数传入也不会有太多的损耗,因为传入的仅仅是一个“描述符”,而不是真正的字符串数据

15.2 字符串的内部表示

//todo

15.3 字符串的高效构造

  • 在能预估出最终字符串长度的情况下,使用预初始化的strings.Builder连接构建字符串效率最高;
  • strings.Join连接构建字符串的平均性能最稳定,如果输入的多个字符串是以[]string承载的,那么strings.Join也是不错的选择;类似implode
  • 使用操作符连接的方式最直观、最自然,在编译器知晓欲连接的字符串个数的情况下,使用此种方式可以得到编译器的优化处理;
  • fmt.Sprintf虽然效率不高,但也不是一无是处,如果是由多种不同类型变量来构建特定格式的字符串,那么这种方式还是最适合的。

15.4 字符串相关的高效转换

下面两种互相转换都要分配新内存

[]byte
b := []byte(s)
ss := string(bb)

[]rune
r := []rune(s)
ss := string(rr)

无需额外分配新内存的转换方式

func convert() {
    s := "中国欢迎您,北京欢迎您"
    sl := []byte(s)
    for _, v := range sl {
        _ = v
    }
}
func convertWithOptimize() {
    s := "中国欢迎您,北京欢迎您"
    for _, v := range []byte(s) {
        _ = v
    }
}

func stringForRangeCovertOptimize() {
    fmt.Println(testing.AllocsPerRun(1, convert)) //1
    fmt.Println(testing.AllocsPerRun(1, convertWithOptimize)) //0
}

关于rune的知识点

// rune is an alias for int32 and is equivalent to int32 in all ways. It is // used, by convention, to distinguish character values from integer values.  
//int32的别名,几乎在所有方面等同于int32 
//它用来区分字符值和整数值  
type rune = int32 

问题:string是怎么转成[]rune的呢?v是什么呢?

  • string通过类型转换,来转成[]rune
  • for range遍历string或[]rune时,v都表示每一个Unicode字符的值(rune类型)
s := "hi,你好吗"
r := []rune(s)
for i, v := range r {
    fmt.Printf("%d %x\n", i, v)
}
for i, v := range s {
    fmt.Printf("%d %x\n", i, v)
}

fmt.Printf("%x", s)

标签:int32,15,string,读书笔记,fmt,字符串,rune,Go
From: https://www.cnblogs.com/brynchen/p/18011129

相关文章

  • Go语言精进之路读书笔记第16条——理解Go语言的包导入
    Go编译速度快的原因主要体现在以下三方面:Go要求每个源文件在开头处显式地列出所有依赖的包导入,这样Go编译器不必读取和处理整个文件就可以确定其依赖的包列表。Go要求包之间不能存在循环依赖。这样一个包的依赖关系便形成了一张有向无环图。由于无环,包可以被单独编译,也可以并行......
  • Django知识笔记1
    本文从分析现在流行的前后端分离Web应用模式说起,然后介绍如何设计RESTAPI,通过使用Django来实现一个RESTAPI为例,明确后端开发RESTAPI要做的最核心工作,然后介绍DjangoRESTframework能帮助我们简化开发RESTAPI的工作。Web应用模式在开发Web应用中,有两种应用模式:前后端不分离......
  • Go语言精进之路读书笔记第14条——了解map实现原理并高效使用
    14.1什么是mapmap对value的类型没有限制,但是对key的类型有严格要求:key的类型应该严格定义了作为“==”和“!=”两个操作符的操作数时的行为,因此func、map、slice、chan不能作为map的key类型。map类型不支持“零值可用”,未显式赋初值的map类型变量的零值为nil。对处于零值状态的......
  • golang类型转换模块之gconv
    gf框架提供了非常强大的类型转换包gconv,可以实现将任何数据类型转换为指定的数据类型,对常用基本数据类型之间的无缝转换,同时也支持任意类型到struct对象的属性赋值。由于gconv模块内部大量使用了断言而非反射(仅struct转换使用到了反射),因此执行的效率非常高。使用方式:import"g......
  • Go语言的For循环:语法全解析
    Go语言,作为一门旨在提供简洁、高效编程体验的编程语言,其循环结构的设计同样体现了这一理念。在Go中,for循环是唯一的循环语句,但它的灵活性足以应对各种迭代需求。本文将详细介绍Go语言中for循环的语法,通过示例展示其在实际编程中的应用。基本语法Go语言的for循环基本语法如下:for初......
  • 详解golang实现一个带时效的环形队列
    1.需求mysql执行时间超过100ms以上打warn日志,但是一分钟以内这种warn日志超过10条就需要告警。所以需求就是获得一分钟以内mysql的warn的个数。2.分析为什么使用环形队列而不使用slice?因为队列长度固定,所以可以一开始就分配好空间,不用自动扩容,环形的目的就是不用改变数组的值,只用移......
  • 【洛谷 P2670】[NOIP2015 普及组] 扫雷游戏 题解(模拟)
    [NOIP2015普及组]扫雷游戏题目背景NOIP2015普及组T2题目描述扫雷游戏是一款十分经典的单机小游戏。在行列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的......
  • 面试经典 150 题 (十四)
    就用除法classSolution{publicint[]productExceptSelf(int[]nums){int[]answer=newint[nums.length];intsum=1;intzeroNum=0;for(inti=0;i<nums.length;i++){if(nums[i]==0)zeroNum++;......
  • Go语言的100个错误使用场景(30-40)|数据类型与字符串使用
    目录前言4.控制结构4.1忽视元素在range循环中是拷贝(#30)4.2忽略在range循环中如何评估表达式(#31)4.3忽略在range中使用指针元素的影响(#32)4.4对map遍历的错误假设(#33)4.5忽略break的作用(#34)4.6在循环中使用defer(#35)5.字符串5.1不理解rune的概念(#36)5.2不准确的字......
  • golang定时器之timer+ticker
    转载: https://juejin.cn/post/7327157426298011663 Timer是一个一次性的定时器,用于在未来的某一时刻执行一次操作。基本使用创建Timer定时器的方式有两种:NewTimer(dDuration)*Timer:该函数接受一个time.Duration类型的参数d(时间间隔),表示定时器在过期之前等待的......