Golang字符串类型——byte、rune、string

本文深入探讨Golang中字符串处理的关键概念,包括string、byte和rune类型的使用,以及它们在ASCII和UTF-8字符集下的表现。通过实例演示了如何在不同场景下选择合适的数据类型进行高效操作。

字符串处理,一般是可以单独立一章讲解的。看看Golang的字符串处理。

一、string、byte这两个都常见。Golang的string,底层是[]byte。对于ASCII字符,Golang默认用1字节;对于汉字,Golang使用UTF-8字符集存储,默认用三个字节。

看个例子,下面的“我爱学习”三个汉字就各占3字节。

package main

import "fmt"

func main() {
	var str1 string = "123我爱学习"

	fmt.Println(len(str1))
}

//输出结果:
15

字符串默认在堆上分配内存存储,是不可变的字节数组,其头部指针指向一个字节数组。

string在内存中的存储结构是长度固定的字节数组,也就是说是字符串是不可变的。当要修改字符串的时候,需要转换为[]byte,修改完成后再转换回来。但是不论怎么转换,都必须重新分配内存,并复制数据,通过加号拼接字符串,每次都必须重新分配内存。

二、byte约等于int8,处理汉字是不合适的。
看下面的例子:
 

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str1 string = "123我爱学习"

	for i:=0; i<len(str1);i++ {
		fmt.Println(str1[i])
		fmt.Println(reflect.TypeOf(str1[i]))
	}
}

//输出结果:
49
uint8
50
uint8
51
uint8
230
uint8
136
uint8
145
uint8
231
uint8
136
uint8
177
uint8
229
uint8
173
uint8
166
uint8
228
uint8
185
uint8
160
uint8

三、Golang有一种类型rune,处理字符串里的UTF-8很适合。
先看看如果直接用range循环字符串的例子:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var str1 string = "123我爱学习"

	for _, v := range str1 {
		fmt.Println(v)
		fmt.Println(reflect.TypeOf(v))
	}
}

//运行结果:
49
int32
50
int32
51
int32
25105
int32
29233
int32
23398
int32
20064
int32

直接是int32类型值,无法看懂。

package main

import (
	"fmt"
)

func main() {
	var str1 string = "123我爱学习"

	rr := []rune(str1)
	for i:=0; i<len(rr);i++ {
		fmt.Printf("%c \n",rr[i])
                fmt.Println(reflect.TypeOf(rr[i]))
	}
}
//输出结果:
1 
int32
2 
int32
3 
int32
我 
int32
爱 
int32
学 
int32
习 
int32

rune实际上就是int32,只不过用来表示字符。

四、小结:

  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符
  • string放在堆,底层是byte[],不可修改。如果一定要改,转成[]byte。

 

 


 

 

<think>嗯,用户想知道在Golang中如何向字符串末尾添加字符。首先,我得回忆一下Golang字符串处理方式。Golang字符串是不可变的,所以直接修改是不可能的。每次对字符串的修改都会生成一个新的字符串。这点我记得没错。 那用户的问题是要在末尾添加字符,应该怎么做呢?可能的方法有几个。比如,使用`+`运算符来连接字符串。例如,原字符串是s,要添加字符c,可以写成s + string(c)。不过,这种方法如果频繁操作的话,效率可能不高,因为每次都会生成新字符串。 另一个方法是使用`fmt.Sprintf`,比如`fmt.Sprintf("%s%c", s, c)`。这种方式也是可行的,但同样需要考虑性能问题,特别是大量操作时。 然后,还有使用`strings.Builder`的方法。这个结构体提供了高效的字符串构建方式。先WriteString字符串,再WriteByte或WriteRune添加字符,最后用String()方法获取结果。这种方法在需要多次追加时效率更高,因为内部使用字节切片,减少了内存分配。 另外,可能要考虑字符的类型。如果是rune类型(比如Unicode字符),需要使用WriteRune,而如果是byte的话,用WriteByte。比如,添加一个中文字符可能需要用WriteRune。 用户可能还会关心性能问题,特别是处理大量数据的时候。这时候,推荐使用strings.Builder,因为它会预分配内存,减少复制次数。比如,假设要循环添加多个字符,用Builder会更高效。 可能还要注意,当添加的字符是单字节的ASCII字符时,可以用简单的`+=`操作,不过这在循环中效率不佳,因为每次都会生成新字符串。这时候还是建议用Builder。 另外,用户可能想知道如何将字符转换为字符串。在Golang中,可以用string()将runebyte转换为字符串。例如,char := 'a',string(char)得到"a"。 还有,可能涉及到字符串和切片的转换。比如,将字符串转为[]rune或[]byte,进行修改后再转回来。不过这种方法在处理单个字符追加时可能不太方便,因为需要处理切片和转换的开销。 总结一下,常用的方法有:直接连接、fmt.Sprintf、strings.Builder。其中,strings.Builder在处理多次追加时性能最好,而直接连接适用于简单情况。用户可能需要根据具体场景选择合适的方法。 另外,用户提供的引用中有提到strings包的一些功能,比如分割、裁剪等,但可能和追加字符不直接相关。不过引用[3]提到字符串处理的各种方法,可能可以引申到使用Builder或者Buffer来处理追加操作。 最后,要确保示例代码正确,比如使用strings.Builder的正确步骤:创建实例,写入原字符串,写入字符,最后获取结果。例如: var builder strings.Builder builder.WriteString("hello") builder.WriteRune('!') result := builder.String() 这样就能得到"hello!"。同样,对于字节,可以用WriteByte。 可能还需要提醒用户注意,当处理大量数据时,预先分配足够的容量可以进一步提高性能,比如使用builder.Grow(n)来预分配空间。 总之,回答时需要覆盖不同的方法,解释它们的适用场景,并给出性能优化的建议。</think>在Go语言中向字符串末尾追加字符可以通过多种方式实现。根据性能需求和场景复杂度,以下是三种常用方法及实现原理分析: ### 一、直接连接操作 使用`+`运算符直接连接字符串: ```go s := "hello" c := '!' result := s + string(c) // 转换为字符串后连接 ``` *适用场景*:简单场景下的单次追加操作 *注意*:频繁操作时会产生大量临时字符串[^3] ### 二、格式化输出 使用`fmt.Sprintf`进行格式化拼接: ```go s := "hello" result := fmt.Sprintf("%s%c", s, '!') // 使用%c格式化字符 ``` *优势*:支持多种数据类型混合拼接 *缺点*:性能低于直接连接操作[^3] ### 三、高效构建方法(推荐) 使用`strings.Builder`实现高效构建: ```go var builder strings.Builder builder.WriteString("hello") // 写入原始字符串 builder.WriteByte('!') // 追加ASCII字符 // 或使用 builder.WriteRune('!') 追加Unicode字符 result := builder.String() ``` *性能优势*: 1. 内部使用字节切片存储,减少内存分配 2. 支持预分配容量 `builder.Grow(n)` 3. 时间复杂度O(n),适合高频次操作[^3] $$ 时间复杂度对比公式 $$ T(n) = \begin{cases} O(1) & \text{单次操作} \\ O(n) & \text{使用Builder的n次操作} \end{cases}$$ ### 四、特殊字符处理 处理多字节字符时应使用`WriteRune`: ```go builder := strings.Builder{} builder.WriteString("你好") builder.WriteRune('!') // 正确追加中文感叹号 fmt.Println(builder.String()) // 输出:你好! ``` 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值