- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Go语言中的字符串拼接方法详情由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
string类型的值可以拆分为一个包含多个字符(rune类型)的序列,也可以被拆分为一个包含多个字节 (byte类型) 的序列。其中一个rune类型值代表一个Unicode 字符,一个rune类型值占用四个字节,底层就是一个 UTF-8 编码值,它其实是int32类型的一个别名类型.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package main
import
(
"fmt"
)
func main() {
str :=
"你好world"
fmt
.Printf(
"The string: %q\n"
, str)
fmt
.Printf(
"runes(char): %q\n"
, []rune(str))
fmt
.Printf(
"runes(hex): %x\n"
, []rune(str))
fmt
.Printf(
"bytes(hex): [% x]\n"
, []byte(str))
}
|
执行结果:
The string: "你好world" runes(char): ['你' '好' 'w' 'o' 'r' 'l' 'd'] runes(hex): [4f60 597d 77 6f 72 6c 64] bytes(hex): e4 bd a0 e5 a5 bd 77 6f 72 6c 64 。
可以看到,英文字符使用一个字节,而中文字符需要三个字节。下面使用 for range 语句对上面的字符串进行遍历:
1
2
3
|
for
index, value := range str {
fmt
.Printf(
"%d: %q [% x]\n"
, index, value, []byte(string(value)))
}
|
执行结果如下:
0: '你' [e4 bd a0] 3: '好' [e5 a5 bd] 6: 'w' [77] 7: 'o' [6f] 8: 'r' [72] 9: 'l' [6c] 10: 'd' [64] 。
index索引值不是0-6,相邻Unicode 字符的索引值不一定是连续的,因为中文字符占用了3个字节,宽度为3.
strings.Builder的优势主要体现在字符串拼接上,相比使用+拼接,效率更高.
strings.Builder
已存在的值不可改变,只能重置(Reset()
方法)或者拼接更多的内容。Builder
值,就不能再以任何方式对其进行复制,比如函数间值传递、通道传递值、把值赋予变量等。Builder
值会自动地对自身的内容容器进行扩容,也可以使用Grow
方法进行手动扩容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package main
import
(
"fmt"
"strings"
)
func main() {
var builder1 strings.Builder
builder1.WriteString(
"hello"
)
builder1.WriteByte(
' '
)
builder1.WriteString(
"world"
)
builder1.Write([]byte{
' '
,
'!'
})
fmt
.Println(builder1.String())
f1 := func(b strings.Builder) {
//
b.WriteString(
"world !"
)
//
会报错
}
f1(builder1)
builder1.Reset()
fmt
.Printf(
"The length 0f builder1: %d\n"
, builder1.Len())
}
|
执行结果:
hello world ! The length 0f builder1: 0 。
strings.Reader类型可以用于高效地读取字符串,它通过使用已读计数机制来实现了高效读取,已读计数保存了已读取的字节数,也代表了下一次读取的起始索引位置.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import
(
"fmt"
"strings"
)
func main() {
reader1 := strings.NewReader(
"hello world!"
)
buf1 :=
make
([]byte, 6)
fmt
.Printf(
"reading index: %d\n"
, reader1.Size()-int64(reader1.Len()))
reader1.Read(buf1)
fmt
.Println(string(buf1))
fmt
.Printf(
"reading index: %d\n"
, reader1.Size()-int64(reader1.Len()))
reader1.Read(buf1)
fmt
.Println(string(buf1))
fmt
.Printf(
"reading index: %d\n"
, reader1.Size()-int64(reader1.Len()))
}
|
执行结果:
reading index: 0 hello reading index: 6 world! reading index: 12 。
可以看到,每读取一次之后,已读计数就会增加.
strings包的ReadAt方法不会依据已读计数进行读取,也不会更新已读计数。它可以根据偏移量来自由地读取Reader值中的内容.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package main
import
(
"fmt"
"strings"
)
func main() {
reader1 := strings.NewReader(
"hello world!"
)
buf1 :=
make
([]byte, 6)
offset1 := int64(6)
n, _ := reader1.ReadAt(buf1, offset1)
fmt
.Println(string(buf2))
}
|
执行结果:
world.
也可以使用Seek方法来指定下一次读取的起始索引位置.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package main
import
(
"fmt"
"strings"
"io"
)
func main() {
reader1 := strings.NewReader(
"hello world!"
)
buf1 :=
make
([]byte, 6)
offset1 := int64(6)
readingIndex, _ := reader2.Seek(offset1, io.SeekCurrent)
fmt
.Printf(
"reading index: %d\n"
, readingIndex)
reader1.Read(buf1)
fmt
.Printf(
"reading index: %d\n"
, reader1.Size()-int64(reader1.Len()))
fmt
.Println(string(buf1))
}
|
执行结果:
reading index: 6 reading index: 12 world.
bytes包和strings包类似,strings包主要面向的是 Unicode 字符和经过 UTF-8 编码的字符串,而bytes包面对的则主要是字节和字节切片,主要作为字节序列的缓冲区。bytes.Buffer数据的读写都使用到了已读计数.
bytes.Buffer具有读和写功能,下面分别介绍他们的简单使用方法.
和strings.Builder一样,bytes.Buffer可以用于拼接字符串,strings.Builder也会自动对内容容器进行扩容。请看下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package main
import
(
"bytes"
"fmt"
)
func DemoBytes() {
var buffer bytes.Buffer
buffer.WriteString(
"hello "
)
buffer.WriteString(
"world !"
)
fmt
.Println(buffer.String())
}
|
执行结果:
hello world .
bytes.Buffer读数据也使用了已读计数,需要注意的是,进行读取操作后,Len方法返回的是未读内容的长度。下面直接来看代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import
(
"bytes"
"fmt"
)
func DemoBytes() {
var buffer bytes.Buffer
buffer.WriteString(
"hello "
)
buffer.WriteString(
"world !"
)
p1 :=
make
([]byte, 5)
n, _ := buffer.Read(p1)
fmt
.Println(string(p1))
fmt
.Println(buffer.String())
fmt
.Printf(
"The length of buffer: %d\n"
, buffer.Len())
}
|
执行结果:
hello world ! The length of buffer: 8 。
简单了解了string类型、strings包和bytes.Buffer类型后,下面来介绍golang中的字符串拼接方法.
https://zhuanlan.zhihu.com/p/349672248 。
go test -bench=. -run=^BenchmarkDemoBytes$ 。
最简单的方法是直接相加,由于string类型的值是不可变的,进行字符串拼接时会生成新的字符串,将拼接的字符串依次拷贝到一个新的连续内存空间中。如果存在大量字符串拼接操作,使用这种方法非常消耗内存.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package main
import
(
"bytes"
"fmt"
"time"
)
func main() {
str1 :=
"hello "
str2 :=
"world !"
str3 := str1 + str2
fmt
.Println(str3)
}
|
前面介绍了strings.Builder可以用于拼接字符串:
1
2
3
|
var builder1 strings.Builder
builder1.WriteString(
"hello "
)
builder1.WriteString(
"world !"
)
|
也可以使用strings.Join方法,其实Join()调用了WriteString方法; 。
1
2
3
4
5
6
|
str1 :=
"hello "
str2 :=
"world !"
str3 :=
""
str3 = strings.Join([]string{str3,str1},
""
)
str3 = strings.Join([]string{str3,str2},
""
)
|
bytes.Buffer也可以用于拼接:
1
2
3
4
|
var buffer bytes.Buffer
buffer.WriteString(
"hello "
)
buffer.WriteString(
"world !"
)
|
也可以使用Go内置函数append方法,用于拼接切片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package main
import
(
"fmt"
)
func DemoAppend(n int) {
str1 :=
"hello "
str2 :=
"world !"
var str3 []byte
str3 = append(str3, []byte(str1)...)
str3 = append(str3, []byte(str2)...)
fmt
.Println(string(str3))
}
|
执行结果:
hello world .
fmt包中的Sprintf方法也可以用来拼接字符串:
1
2
3
|
str1 :=
"hello "
str2 :=
"world !"
str3 :=
fmt
.Sprintf(
"%s%s"
, str1, str2)
|
下面来测试一下这6种方法的性能,编写测试源码文件strcat_test.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
package benchmark
import
(
"bytes"
"fmt"
"strings"
"testing"
)
func DemoBytesBuffer(n int) {
var buffer bytes.Buffer
for
i := 0; i < n; i++ {
buffer.WriteString(
"hello "
)
buffer.WriteString(
"world !"
)
}
}
func DemoWriteString(n int) {
var builder1 strings.Builder
for
i := 0; i < n; i++ {
builder1.WriteString(
"hello "
)
builder1.WriteString(
"world !"
)
}
}
func DemoStringsJoin(n int) {
str1 :=
"hello "
str2 :=
"world !"
str3 :=
""
for
i := 0; i < n; i++ {
str3 = strings.Join([]string{str3, str1},
""
)
str3 = strings.Join([]string{str3, str2},
""
)
}
}
func DemoPlus(n int) {
str1 :=
"hello "
str2 :=
"world !"
str3 :=
""
for
i := 0; i < n; i++ {
str3 += str1
str3 += str2
}
}
func DemoAppend(n int) {
str1 :=
"hello "
str2 :=
"world !"
var str3 []byte
for
i := 0; i < n; i++ {
str3 = append(str3, []byte(str1)...)
str3 = append(str3, []byte(str2)...)
}
}
func DemoSprintf(n int) {
str1 :=
"hello "
str2 :=
"world !"
str3 :=
""
for
i := 0; i < n; i++ {
str3 =
fmt
.Sprintf(
"%s%s"
, str3, str1)
str3 =
fmt
.Sprintf(
"%s%s"
, str3, str2)
}
}
func BenchmarkBytesBuffer(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoBytesBuffer(10000)
}
}
func BenchmarkWriteString(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoWriteString(10000)
}
}
func BenchmarkStringsJoin(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoStringsJoin(10000)
}
}
func BenchmarkAppend(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoAppend(10000)
}
}
func BenchmarkPlus(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoPlus(10000)
}
}
func BenchmarkSprintf(b *testing.B) {
for
i := 0; i < b.N; i++ {
DemoSprintf(10000)
}
}
执行性能测试:
$ go
test
-bench=. -run=^$
goos: windows
goarch: amd64
pkg: testGo
/benchmark
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
BenchmarkBytesBuffer-8 3436 326846 ns
/op
BenchmarkWriteString-8 4148 271453 ns
/op
BenchmarkStringsJoin-8 3 402266267 ns
/op
BenchmarkAppend-8 1923 618489 ns
/op
BenchmarkPlus-8 3 345087467 ns
/op
BenchmarkSprintf-8 2 628330850 ns
/op
PASS
ok testGo
/benchmark
9.279s
|
通过平均耗时可以看到WriteString方法执行效率最高。Sprintf方法效率最低.
Strings.Join
方法效率也比较低,在上面的场景下它的效率比较低,它在合并已有字符串数组的场合效率是很高的。WriteString
方法,如果是少量字符串拼接,也可以直接使用+。append
方法的效率也是很高的,它主要用于切片的拼接。fmt.Sprintf
方法虽然效率低,但在少量数据拼接中,如果你想拼接其它数据类型,使用它可以完美的解决:
1
2
3
4
|
name :=
"zhangsan"
age := 20
str4 :=
fmt
.Sprintf(
"%s is %d years old"
, name, age)
fmt
.Println(str4)
//
zhangsan is 20 years old
|
到此这篇关于Go语言中的字符串拼接方法详情的文章就介绍到这了,更多相关Go语言中的字符串拼接方法内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/u010698107/article/details/120097937 。
最后此篇关于Go语言中的字符串拼接方法详情的文章就讲到这里了,如果你想了解更多关于Go语言中的字符串拼接方法详情的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
至少在某些 ML 系列语言中,您可以定义可以执行模式匹配的记录,例如http://learnyouahaskell.com/making-our-own-types-and-typeclasses -
这可能是其他人已经看到的一个问题,但我正在尝试寻找一种专为(或支持)并发编程而设计的语言,该语言可以在 .net 平台上运行。 我一直在 erlang 中进行辅助开发,以了解该语言,并且喜欢建立一个稳
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be
我正在寻找一种进程间通信工具,可以在相同或不同系统上运行的语言和/或环境之间使用。例如,它应该允许在 Java、C# 和/或 C++ 组件之间发送信号,并且还应该支持某种排队机制。唯一明显与环境和语言
我有一些以不同语言返回的文本。现在,客户端返回的文本格式为(en-us,又名美国英语): Stuff here to keep. -- Delete Here -- all of this below
问题:我希望在 R 中找到类似 findInterval 的函数,它为输入提供一个标量和一个表示区间起点的向量,并返回标量落入的区间的索引。例如在 R 中: findInterval(x = 2.6,
我是安卓新手。我正在尝试进行简单的登录 Activity ,但当我单击“登录”按钮时出现运行时错误。我认为我没有正确获取数据。我已经检查过,SQLite 中有一个与该 PK 相对应的数据。 日志猫。
大家好,感谢您帮助我。 我用 C# 制作了这个计算器,但遇到了一个问题。 当我添加像 5+5+5 这样的东西时,它给了我正确的结果,但是当我想减去两个以上的数字并且还想除或乘以两个以上的数字时,我没有
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 4 年前。 Improve th
这就是我所拥有的 #include #include void print(int a[], int size); void sort (int a[], int size); v
你好,我正在寻找我哪里做错了? #include #include int main(int argc, char *argv[]) { int account_on_the_ban
嘿,当我开始向数组输入数据时,我的代码崩溃了。该程序应该将数字读入数组,然后将新数字插入数组中,最后按升序排列所有内容。我不确定它出了什么问题。有人有建议吗? 这是我的代码 #include #in
我已经盯着这个问题好几个星期了,但我一无所获!它不起作用,我知道那么多,但我不知道为什么或出了什么问题。我确实知道开发人员针对我突出显示的行吐出了“错误:预期表达式”,但这实际上只是冰山一角。如果有人
我正在编写一个点对点聊天程序。在此程序中,客户端和服务器功能写入一个唯一的文件中。首先我想问一下我程序中的机制是否正确? I fork() two processes, one for client
基本上我需要找到一种方法来发现段落是否以句点 (.) 结束。 此时我已经可以计算给定文本的段落数,但我没有想出任何东西来检查它是否在句点内结束。 任何帮助都会帮助我,谢谢 char ch; FI
我的函数 save_words 接收 Armazena 和大小。 Armazena 是一个包含段落的动态数组,size 是数组的大小。在这个函数中,我想将单词放入其他称为单词的动态数组中。当我运行它时
我有一个结构 struct Human { char *name; struct location *location; int
我正在尝试缩进以下代码的字符串输出,但由于某种原因,我的变量不断从文件中提取,并且具有不同长度的噪声或空间(我不确定)。 这是我的代码: #include #include int main (v
我想让用户选择一个选项。所以我声明了一个名为 Choice 的变量,我希望它输入一个只能是 'M' 的 char 、'C'、'O' 或 'P'。 这是我的代码: char Choice; printf
我正在寻找一种解决方案,将定义和变量的值连接到数组中。我已经尝试过像这样使用 memcpy 但它不起作用: #define ADDRESS {0x00, 0x00, 0x00, 0x00, 0x0
我是一名优秀的程序员,十分优秀!