go语言中的string

此专题是因为自己在刷题时老是对string利用不当,特地整理

string

以下内容来自gpt
在 Go 语言中,字符串(string)是一个包含了一系列字符(Unicode码点)的不可变序列。字符串在 Go 语言中是一个内置的数据类型,使用起来非常方便。以下是关于 Go 语言中字符串的一些详细说明:

  1. 不可变性:字符串是不可变的,这意味着一旦创建了一个字符串,就无法直接修改其内容。如果需要修改字符串,通常需要将其转换为可变的字节切片,进行修改后再转换回字符串。

  2. 字节表示:字符串实际上是一个字节切片([]byte)的只读视图。每个字符在字符串中占用的字节数取决于该字符的 Unicode 编码。在字符串中,每个 Unicode 码点都可能占用多个字节。

  3. Unicode 支持:Go 的字符串类型支持 Unicode,这意味着它可以存储任何 Unicode 字符,包括中文、日文、希腊字母等等。

  4. 字面值表示:在 Go 中,用双引号 " 包裹的字符序列表示一个字符串字面值。例如:"Hello, 世界!"。另外,还可以使用反引号 ` 包裹的字符序列,这种方式表示的字符串会保留其原始格式,包括换行符和特殊字符。

  5. 字符串连接:可以使用加号 + 来连接字符串,例如:"Hello" + " " + "World"

  6. 长度:通过内置函数 len() 可以获取字符串的长度,即其中字符的数量。

  7. 索引访问:可以通过索引来访问字符串中的单个字符。在 Go 中,字符串是 UTF-8 编码的,因此一个字符可能由多个字节组成。可以使用索引访问字符串中的单个字节,也可以使用 Unicode 码点的索引访问字符。例如,str[0] 可以获取字符串中的第一个字节,而 rune(str[0]) 可以将其转换为 Unicode 码点。

  8. 字符串迭代:可以使用 for range 循环来迭代字符串中的 Unicode 字符。每次迭代,range 会返回当前字符的 Unicode 码点及其字节位置。

  9. 字符串切片:可以使用切片操作来获取字符串的子串。例如,str[1:4] 可以获取字符串中从索引 1 到索引 3(不包含索引 4)的子串。

  10. 字符串比较:可以使用 ==!= 操作符来比较两个字符串是否相等。此外,可以使用 <<=>>= 操作符进行字符串的大小比较,这些比较会按照字典顺序进行。

总的来说,Go 语言中的字符串类型提供了丰富的功能和便捷的操作,使得处理文本数据变得非常简单和高效。

package main

import (
    "fmt"
)

func main() {
    s := "你好,世界!"
    
    // 使用 range 遍历字符串,x 是一个 Unicode 字符
    for _, x := range s {
        fmt.Printf("字符:%c,ASCII 码值:%d\n", x, x)
    }
}

字符:你,ASCII 码值:20320
字符:好,ASCII 码值:22909
字符:,,ASCII 码值:65292
字符:世,ASCII 码值:19990
字符:界,ASCII 码值:30028
字符:!,ASCII 码值:65281

package main

import (
    "fmt"
)

func main() {
    s := "你好,世界!"
    
    // 使用索引遍历字符串,s[i] 是一个字节
    for i := 0; i < len(s); i++ {
        fmt.Printf("字节:%c,ASCII 码值:%d\n", s[i], s[i])
    }
}

字节:你,ASCII 码值:228
字节:好,ASCII 码值:229
字节:,,ASCII 码值:239
字节:世,ASCII 码值:199
字节:界,ASCII 码值:191
字节:!,ASCII 码值:161

在 Go 语言中,xrune 类型,而 s[i]byte 类型。

  • rune 类型用于表示 Unicode 码点,它是 int32 的别名。在遍历字符串时,range 关键字会自动将字符串转换为 rune 类型,这样可以确保正确处理 Unicode 字符。
  • byte 类型用于表示单个字节,即 8 位二进制数。在遍历字符串时,按索引访问字符串会得到该位置的字节值。

所以,在使用 for _, x := range s 遍历字符串时,x 是一个 Unicode 字符,类型为 rune。而在使用 for i := 0; i < len(s); i++ { s[i] } 的方式中,s[i] 是一个字节,类型为 byte

对于string而言有个最重要的特性不可变性
在 Go 语言中,字符串是不可变的,这意味着一旦创建了一个字符串,就无法直接修改其内容。这是因为字符串在内存中是以只读的方式存储的,即字符串的内容是不可更改的。这个特性带来了一些好处和挑战:

好处:

  1. 线程安全: 字符串的不可变性使得在多线程环境下对字符串的访问更加安全,无需担心并发修改带来的问题。
  2. 内存优化: 由于字符串是不可变的,可以在内存中共享相同的字符串值,节省内存空间。

挑战:

  1. 效率问题: 每次对字符串进行修改时,都需要创建一个新的字符串,而不是直接在原字符串上进行修改。这样可能会导致内存开销较大,尤其是对于频繁修改的场景。
  2. 拷贝问题: 当对字符串进行切片或者拼接操作时,可能会导致底层数据的拷贝,从而增加额外的开销。

解决办法:

尽管字符串是不可变的,但是在实际开发中,我们可以采取一些策略来解决字符串不可变性带来的问题:

  1. 使用字节切片: 如果需要频繁地对字符串进行修改,可以将字符串转换为可变的字节切片([]byte),然后在切片上进行修改。修改完成后,可以再将字节切片转换回字符串。需要注意的是,这样做会导致额外的内存开销和拷贝操作。

  2. 使用 strings 包中的函数: Go 标准库的 strings 包提供了许多用于处理字符串的函数,这些函数通常会返回一个新的字符串而不是修改原始字符串。使用这些函数可以避免直接修改字符串的需求。

  3. 使用字符串构建器(strings.Builder): 如果需要进行大量的字符串拼接操作,可以使用 strings.Builder 类型来构建字符串。strings.Builder 类型提供了高效的字符串拼接功能,避免了频繁的字符串拷贝操作。

  4. 避免频繁修改字符串: 尽量设计避免频繁修改字符串的算法和数据结构,可以通过预先分配足够的内存空间或者使用合适的数据结构来降低字符串的修改次数。

综上所述,虽然字符串是不可变的,但是在实际应用中,通过合理的设计和使用适当的方法,我们可以有效地处理字符串,并且避免不可变性带来的问题。

下面是举几个例子来详细说明解决字符串不可变性带来的问题以及解决办法:

1. 需要修改字符串中的某个字符

假设我们有一个字符串,需要将其中某个字符替换为另一个字符。由于字符串是不可变的,直接修改字符串是不允许的。我们可以使用字节切片来解决这个问题:

package main

import "fmt"

func main() {
    s := "hello"
    
    // 将字符串转换为字节切片
    b := []byte(s)
    
    // 修改字节切片中的某个字节
    b[0] = 'H'
    
    // 将字节切片转换回字符串
    s = string(b)
    
    fmt.Println(s) // 输出:Hello
}

在这个例子中,我们将字符串 "hello" 转换为字节切片 b,然后修改了切片中的第一个字节,最后将修改后的字节切片重新转换回字符串。

2. 需要进行字符串拼接操作

假设我们需要对多个字符串进行拼接操作,但由于字符串不可变性,每次拼接字符串都会创建一个新的字符串,导致性能下降。我们可以使用 strings.Builder 类型来构建字符串:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var builder strings.Builder
    
    // 构建字符串
    builder.WriteString("Hello, ")
    builder.WriteString("World!")
    
    // 获取拼接后的字符串
    result := builder.String()
    
    fmt.Println(result) // 输出:Hello, World!
}

在这个例子中,我们使用 strings.Builder 类型来构建字符串,使用 WriteString 方法进行字符串的拼接操作。最后通过 String 方法获取拼接后的最终字符串。

3. 遍历字符串并统计字符出现次数

假设我们需要遍历字符串并统计其中每个字符的出现次数。我们可以使用 map[rune]int 类型来统计字符出现次数:

package main

import (
    "fmt"
)

func main() {
    s := "hello"
    
    // 使用 map 统计字符出现次数
    freq := make(map[rune]int)
    for _, r := range s {
        freq[r]++
    }
    
    // 输出字符出现次数
    for char, count := range freq {
        fmt.Printf("字符 %c 出现了 %d 次\n", char, count)
    }
}

在这个例子中,我们使用 map[rune]int 类型来统计字符出现次数,rune 类型用于表示 Unicode 码点,这样可以正确处理字符串中的 Unicode 字符。遍历字符串时,将每个字符作为键存储在 freq map 中,并统计其出现次数。

通过这些例子,我们可以看到如何使用不同的方法来解决字符串不可变性带来的问题,从而更有效地处理字符串。

strings常用函数

在 Go 语言的 strings 包中有许多常用的函数,用于处理字符串。以下是其中几个常用函数的介绍:

  1. len(s string) int 返回字符串 s 的字节数(即字符串的长度)。注意,由于 Go 中的字符串是 UTF-8 编码的,一个 Unicode 字符可能占用多个字节,因此 len() 返回的是字符串的字节数,而不是字符数。

  2. strings.Contains(s, substr string) bool 判断字符串 s 是否包含子串 substr,如果包含则返回 true,否则返回 false

  3. strings.HasPrefix(s, prefix string) boolstrings.HasSuffix(s, suffix string) bool 分别用于判断字符串 s 是否以指定的前缀 prefix 或后缀 suffix 开始或结束,如果是则返回 true,否则返回 false

  4. strings.Index(s, substr string) intstrings.LastIndex(s, substr string) int 分别返回字符串 s 中子串 substr 的第一次和最后一次出现的索引位置(如果没有找到则返回 -1)。

  5. strings.Replace(s, old, new string, n int) string 将字符串 s 中的所有子串 old 替换为子串 new,如果指定了 n,则最多替换 n 个匹配项。返回替换后的新字符串。

  6. strings.Split(s, sep string) []string 使用分隔符 sep 将字符串 s 分割成多个子串,并返回一个切片。如果 sep 为空,则将字符串切分为每个 Unicode 字符一个子串。

  7. strings.ToLower(s string) stringstrings.ToUpper(s string) string 分别将字符串 s 中的所有字符转换为小写或大写,并返回新的字符串。

  8. strings.TrimSpace(s string) string 去除字符串 s 前后的所有空白字符,并返回新的字符串。空白字符包括空格、制表符、换行符等。

这些函数是 strings 包中的一部分,可以方便地进行字符串处理,常用于文本处理、字符串匹配、分割、替换等操作。在实际开发中,经常会用到这些函数来处理字符串数据。

strconv常用函数

在 Go 语言的 strconv 包中提供了一系列用于字符串和基本数据类型之间转换的函数。以下是 strconv 包中一些常用的函数:

  1. strconv.Atoi(s string) (int, error) 将字符串 s 转换为整数 int。如果转换成功,返回转换后的整数和 nil;如果转换失败,则返回 0 和一个非 nil 的错误。

  2. strconv.ParseInt(s string, base int, bitSize int) (int64, error) 将字符串 s 解析为指定进制的整数 int64。参数 base 指定了进制,可以是 0 表示自动推断进制,或者 281016。参数 bitSize 指定了结果的位大小(08163264)。

  3. strconv.ParseFloat(s string, bitSize int) (float64, error) 将字符串 s 解析为浮点数 float64。参数 bitSize 指定了结果的精度(32 或 64)。如果转换成功,返回转换后的浮点数和 nil;如果转换失败,则返回 0 和一个非 nil 的错误。

  4. strconv.Itoa(i int) string 将整数 i 转换为字符串。该函数是 strconv.Itoa(i) 的简写形式。

  5. strconv.FormatInt(i int64, base int) stringstrconv.FormatFloat(f float64, fmt byte, prec, bitSize int) string 分别用于将整数 i 和浮点数 f 格式化为字符串。参数 basefmt 分别表示进制和格式,prec 表示精度,bitSize 表示位大小。

  6. strconv.Quote(s string) stringstrconv.QuoteToASCII(s string) string 将字符串 s 转换为带引号的字符串。Quote 函数会按照 Go 语法转义非 ASCII 字符,而 QuoteToASCII 函数会将非 ASCII 字符转换为 \u 格式的 Unicode 转义序列。

  7. strconv.Unquote(s string) (string, error) 将带引号的字符串 s 转换为原始字符串。如果转换成功,返回去除引号后的字符串和 nil;如果转换失败,则返回 s 和一个非 nil 的错误。

  8. strconv.AppendInt(dst []byte, i int64, base int) []bytestrconv.AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte 分别用于将整数 i 和浮点数 f 追加到字节切片 dst 中,返回追加后的字节切片。

这些函数是 strconv 包中一些常用的函数,用于字符串和基本数据类型之间的转换。在处理文本数据、解析用户输入等场景中,这些函数经常会被使用到。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 作者:李骁 10.1 字符串介绍 Go 语言中可以使用反引号或者双引号来定义字符串。反引号表示原生的字符串,即不进...
    ffhelicopter阅读 1,721评论 2 3
  • 最近研读了下go语言,所以想整理一番 string 在go中如何定义的?string 的底层原理与细节?strin...
    Tim在路上阅读 5,291评论 1 2
  • Go中的字符串(string)和切片([]byte)的差异、对比、以及互相转换string和[]byte的说明 s...
    __sk阅读 3,875评论 2 1
  • Go 语言中包括以下内置基础类型: 布尔型:bool 整型: int64 int32 int16 int8 uin...
    wayyyy阅读 356评论 0 0
  • 一、位运算符概述 * 位运算时,需要知道几个概念:原码、反码、补码。正数在计算机中二进制还是原值,负数在计算机中存...
    小陈工阅读 158评论 0 2