0%

泛型程序设计(generic programming)是一种算法在实现时不指定具体要操作的数据的类型的程序设计方法。所谓 "泛型",指的是算法只要实现一遍,就能适用于多种数据类型。泛型程序设计方法的优势在于能够减少重复代码的编写。

泛型程序设计的概念最早出现于 1983 年的 Ada 语言,其最成功的应用就是 C++ 的标准模板库(STL)。也可以说,泛型程序设计就是大量编写模板、使用模板的程序设计。泛型程序设计在 C++ 中的重要性和带来的好处不亚于面向对象的特性。

在 C++ 中,模板分为函数模板和类模板两种。熟练的 C++ 程序员,在编写函数时都会考虑能否将其写成函数模板,编写类时都会考虑能否将其写成类模板,以便实现重用。

C++ 函数模板

考虑一下交换两个变量的值的函数,如下,我们可以通过定义不同类型的重载函数实现对不同类型的两个值的交换。下面我们定义了四个名字相同、参数列表不同的函数。

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
// 交换 int 变量的值
void Swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}

// 交换 float 变量的值
void Swap(float *a, float *b) {
float temp = *a;
*a = *b;
*b = temp;
}

// 交换 char 变量的值
void Swap(char *a, char *b) {
char temp = *a;
*a = *b;
*b = temp;
}

// 交换 bool 变量的值
void Swap(bool *a, bool *b) {
bool temp = *a;
*a = *b;
*b = temp;
}

这些函数虽然在调用时方便了一些,但从本质上说还是定义了四个功能相同、函数体相同的函数,只是数据的类型不同而已,这看起来有点啰嗦,能不能把它们压缩成一个函数呢?

能,可以借助函数模板。

我们知道,数据的值可以通过函数参数传递,在函数定义时数据的值是未知的,只有等到函数调用时接收了实参才能确定其值。这就是值的参数化。

在 C++ 中,数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当发生函数调用时,编译器可以根据传入的实参自动推断数据类型。这就是类型的参数化。

值(Value)和类型(Type)是数据的两个主要特征,它们在 C++ 中都可以被参数化。

所谓函数模板,实际上是建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板(Function Template)。

在函数模板中,数据的值和类型都被参数化了,发生函数调用时编译器会根据传入的实参来推演形参的值和类型。换个角度说,函数模板除了支持值的参数化,还支持类型的参数化。

一旦定义了函数模板,就可以将类型参数用于定义函数定义和函数声明了。说得直白一点,原来使用 int、float、char 等内置类型的地方,都可以用类型参数来代替。

下面来实践一下,将上面的四个 Swap() 函数压缩为一个函数模板。

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
#include<iostream>
using namespace std;

template <typename T> void Swap(T *a, T *b) {
T temp = *a;
*a = *b;
*b = temp;
}

int main() {
// 交换 int 变量的值
int n1 = 100, n2 = 200;
Swap(&n1, &n2);
cout << n1 << ", " << n2 << endl;

// 交换 float 变量的值
float f1 = 12.5, f2 = 56.1;
Swap(&f1, &f2);
cout << f1 << ", " << f2 << endl;

// 交换 char 变量的值
char c1 = 'A', c2 = 'B';
Swap(&c1, &c2);
cout << c1 << ", " << c2 << endl;

// 交换 bool 变量的值
bool b1 = false, b2 = true;
Swap(&b1, &b2);
cout << b1 << ", " << b2 << endl;

return 0;
}

运行结果:

1
2
3
4
200, 100
56.1, 12.5
B, A
1, 0

请读者重点关注第 4 行代码。template 是定义函数模板的关键字,它后面紧跟尖括号 <>,尖括号包围的是类型参数(也可以说是虚拟的类型,或者说是类型占位符)。typename 是另外一个关键字,用来声明具体的类型参数,这里的类型参数就是 T。从整体上看,template<typename T> 被称为模板头。

模板头中包含的类型参数可以用在函数定义的各个位置,包括返回值、形参列表和函数体;本例我们在形参列表和函数体中使用了类型参数 T。

类型参数的命名规则跟其他标识符的命名规则意义,不过使用 T、T1、T2 Type 等已经成为了一种惯例。

定义了函数模板之后,就可以像调用普通函数一样来调用它们了。

引用形参版本:

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
#include<iostream>
using namespace std;

template <typename T> void Swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}

int main() {
// 交换 int 变量的值
int n1 = 100, n2 = 200;
Swap(n1, n2);
cout << n1 << ", " << n2 << endl;

// 交换 float 变量的值
float f1 = 12.5, f2 = 56.1;
Swap(f1, f2);
cout << f1 << ", " << f2 << endl;

// 交换 char 变量的值
char c1 = 'A', c2 = 'B';
Swap(c1, c2);
cout << c1 << ", " << c2 << endl;

// 交换 bool 变量的值
bool b1 = false, b2 = true;
Swap(b1, b2);
cout << b1 << ", " << b2 << endl;

return 0;
}

引用不但使得函数定义简洁明了,也使得调用函数方便了很多。整体来看,引用让编码更加漂亮。

下面我们来总结一下定义模板函数的语法:

1
2
3
template<typename 类型参数1, typename 类型参数2, ...> 返回值类型 函数名(形参列表) {
// 在函数体中可以使用类型参数
}

类型参数可以有多个,它们之间以逗号 , 分隔。类型参数列表以 <> 包围,形式参数列表以 () 包围。

typename 关键字也可以使用 class 关键字替代,它们没有任何区别。C++ 早期对模板的支持并不严谨,没有引入新的关键字,而是用 class 来指明类型参数,但是 class 关键字本来已经用在类的定义中了,这样做显得不太友好,所以后来 C++ 又引入了一个新的关键字 typename,专门用来定义类型参数。不过至今仍然有很多代码在使用 class 关键字,包括 C++ 标准库、一些开源程序等。

上面的 Swap 也可以使用 class 来指明类型参数:

1
2
3
4
5
template<class T> void Swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}

除了将 typename 替换为 class,其他都是一样的。

为了加深对函数模板的理解,我们再来看一个求三个数的最大值的例子:

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
#include<iostream>
using namespace std;

// 声明函数模板
template <typename T> T max(T a, T b, T c);

int main()
{
// 求三个整数的最大值
int i1, i2, i3, i_max;
cin >> i1 >> i2 >> i3;
i_max = max(i1, i2, i3);
cout << "i_max=" << i_max << endl;

// 求三个浮点数的最大值
double d1, d2, d3, d_max;
cin >> d1 >> d2 >> d3;
d_max = max(d1, d2, d3);
cout << "d_max=" << d_max << endl;

// 求三个长整型数的最大值
long g1, g2, g3, g_max;
cin >> g1 >> g2 >> g3;
g_max = max(g1, g2, g3);
cout << "g_max=" << g_max << endl;

return 0;
}

// 定义函数模板
template <typename T> // 模板头,这里不能有分号
T max(T a, T b, T c) { // 函数头
T max_num = a;
if (b > max_num) max_num = b;
if (c > max_num) max_num = c;
return max_num;
}

输出:

1
2
3
4
5
6
12 34 100
i_max=100
72.3 90.3 88.1
d_max=90.3
344 900 589
g_max=900

函数模板也可以提前声明,不过声明时需要带上模板头,并且模板头和函数定义(声明)是一个不可分割的整体,它们可以换行,但中间不能有分号。

1
export ALL_PROXY=socks5://127.0.0.1:1086

1086 是 ShadowSocks 的 socks5 流量监听端口

然后执行 brew 命令。

前提:有 ShadowSocks

安装步骤

  1. 下载最新版的 proxychains-ng

  2. 编译安装,详细可以看官方 readme

1
2
3
4
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install
sudo make install-config
  1. 修改 proxychains 配置文件

vim /etc/proxychains.conf

1
2
# 把最后一行改成下面的,1086 改成本地的 sock5 监听的端口
socks5 0.0.0.0 1086
  1. 测试
1
proxychains4 telnet google.com 80

git clone 使用 proxychains

1
proxychains4 git clone https://github.com/php/php-src.git

用法就是在命令前面加上 proxychians

其他可以尝试一下的方式

git-clone-works-with-https-but-not-ssh-when-using-proxy

  1. 常量
  2. 变量
  3. 函数
  4. Buffer
  5. Buffer 方法
  6. Reader
  7. Reader 方法

常量

MinRead 是传递给 Buffer.ReadFrom 方法的最小切片大小。只要 Buffer 里面的内容长度没有超出 MinRead 个字节,ReadFrom 不会增长 Buffer 里面的缓冲区大小。

1
const MinRead = 512

变量

当内存装不下需要放入 buffer 的数据的时候,会抛出一个 panic,内容就是 ErrTooLarge

1
var ErrTooLarge = errors.New("bytes.Buffer: too large")

函数

Compare

1
func Compare(a, b []byte) int

按字典顺序比较两个字节切片。如果 a == b,返回 0,如果 a < b 返回 -1,如果 a > b 返回 1。

点此查看实例
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
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleCompare() {
// 通过将结果与零进行比较来解释比较结果
var a, b []byte

a = []byte("a")
b = []byte("b")
if bytes.Compare(a, b) < 0 {
// a 小于 b
fmt.Printf("a = '%s', b = '%s', a < b\n", a, b)
}

a = []byte("a")
b = []byte("a")
if bytes.Compare(a, b) <= 0 {
// a 小于或等于 b
fmt.Printf("a = '%s', b = '%s', a <= b\n", a, b)
}

a = []byte("b")
b = []byte("a")
if bytes.Compare(a, b) > 0 {
// a 大于 b
fmt.Printf("a = '%s', b = '%s', a > b\n", a, b)
}

a = []byte("b")
b = []byte("b")
if bytes.Compare(a, b) >= 0 {
// a 大于或等于 b
fmt.Printf("a = '%s', b = '%s', a >= b\n", a, b)
}

// 判断两个字节切片是否相等
if bytes.Equal(a, b) {
// a 等于 b
fmt.Printf("a = '%s', b = '%s', a == b\n", a, b)
}
b = []byte("c")
if !bytes.Equal(a, b) {
// a 不等于 b
fmt.Printf("a = '%s', b = '%s', a != b\n", a, b)
}

// Output:
// a = 'a', b = 'b', a < b
// a = 'a', b = 'a', a <= b
// a = 'b', b = 'a', a > b
// a = 'b', b = 'b', a >= b
// a = 'b', b = 'b', a == b
// a = 'b', b = 'c', a != b
}

func ExampleSearch() {
var needle []byte
var haystack [][]byte // 假设是有序的

// 模拟测试数据
needle = []byte("ccb")
haystack = [][]byte{
[]byte("cca"),
[]byte("ccb"),
[]byte("ccc"),
}

// haystack 需要是有序的
i := sort.Search(len(haystack), func(i int) bool {
// Return haystack[i] >= needle.
return bytes.Compare(haystack[i], needle) >= 0
})
if i < len(haystack) && bytes.Equal(haystack[i], needle) {
fmt.Println("Found it!")
}

// Output:
// Found it!
}

Contains

1
func Contains(b, subslice []byte) bool

检查 b 里面是否包含了 subslice 字节序列。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleContains() {
fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
fmt.Println(bytes.Contains([]byte("seafood"), []byte("")))
fmt.Println(bytes.Contains([]byte(""), []byte("")))

// Output:
// true
// false
// true
// true
}

ContainsAny

1
func ContainsAny(b []byte, chars string) bool

ContainsAny 检查字符串 chars utf-8编码的字符切片里面是否有任何字节在 b 里面。

chars 是空字符串的时候都返回 false

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleContainsAny() {
fmt.Println(bytes.ContainsAny([]byte("I like seafood."), "fAo!"))
fmt.Println(bytes.ContainsAny([]byte("I like seafood."), "去是伟大的."))
fmt.Println(bytes.ContainsAny([]byte("I like seafood."), ""))
fmt.Println(bytes.ContainsAny([]byte(""), ""))

// Output:
// true
// true
// false
// false
}

ContainsRune

1
func ContainsRune(b []byte, r rune) bool

rune 可以简单看作是字符类型(可以是多字节字符)。

ContainsRune 检查 r 是否出现在 utf-8 编码的字节序列中。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleContainsRune() {
fmt.Println(bytes.ContainsRune([]byte("I like seafood."), 'f'))
fmt.Println(bytes.ContainsRune([]byte("I like seafood."), 'ö'))
fmt.Println(bytes.ContainsRune([]byte("去是伟大的!"), '大'))
fmt.Println(bytes.ContainsRune([]byte("去是伟大的!"), '!'))
fmt.Println(bytes.ContainsRune([]byte(""), '@'))

// Output:
// true
// false
// true
// true
// false
}

Count

1
func Count(s, sep []byte) int

Count 用来计算 sep 出现在 s 中的次数,其中 s 是 utf-8 编码的字节序列。

如果 sep 为空,则返回 s 的长度 + 1

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleCount() {
fmt.Println(bytes.Count([]byte("cheese"), []byte("e")))
// before & after each rune
fmt.Println(bytes.Count([]byte("five"), []byte("")))

// Output:
// 3
// 5
}

Equal

1
func Equal(a, b []byte) bool

Equal 判断字节切片 ab 的是否相等。如果传 nil,则视作空切片。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleEqual() {
fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))

// Output:
// true
// false
}

EqualFold

1
func EqualFold(s, t []byte) bool

EqualFold 比较 UTF-8 编码是否相等,不区分大小写。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleEqualFold() {
fmt.Println(bytes.EqualFold([]byte("Go"), []byte("go")))

// Output:
// true
}

Fields

1
func Fields(s []byte) [][]byte

Fields 将参数当作一个 UTF-8 编码的字节切片,根据 unicode.IsSpace 定义的空白字符来拆分该字节切片,但是拆分的结果不会包含空白字符。如果只包含空白字符,则返回一个空的二维切片。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleFields() {
fmt.Printf("Fields are: %q\n", bytes.Fields([]byte(" foo bar baz ")))

// Output:
// Fields are: ["foo" "bar" "baz"]
}

FieldsFunc

1
func FieldsFunc(s []byte, f func(rune) bool) [][]byte

Fields 类似,只不过这里接收一个回调让用户可以返回一个布尔值,系统根据返回值决定是否使用这个字符来分割 Field。如果所有的字符都满足 f(r) 或者字节切片 s 的长度为 0,FieldsFunc 返回一个空的切片。FieldsFunc 不保证其调用 f(c) 的顺序。如果 f 对于给定的 c 没有返回一致的结果,则 FieldsFunc 可能会崩溃。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleFieldsFunc() {
f := func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
}
fmt.Printf("Fields are: %q\n", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f))

// Output:
// Fields are: ["foo1" "bar2" "baz3"]
}

HasPrefix

1
func HasPrefix(s, prefix []byte) bool

HasPrefix 检查字节切片是否以 prefix 切片开头。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleHasPrefix() {
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("")))

// Output:
// true
// false
// true
}

HasSuffix

1
func HasSuffix(s, suffix []byte) bool

HasPrefix 检查字节切片 s 是否以字节切片 prefix 结尾。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleHasSuffix() {
fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("go")))
fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("O")))
fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("Ami")))
fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("")))

// Output:
// true
// false
// false
// true
}

Index

1
func Index(s, sep []byte) int

Index 返回 seps 中的下标,如果 sep 不在 s 中则返回 -1。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleIndex() {
fmt.Println(bytes.Index([]byte("chicken"), []byte("ken")))
fmt.Println(bytes.Index([]byte("chicken"), []byte("dmr")))

// Output:
// 4
// -1
}

IndexAny

1
func IndexAny(s []byte, chars string) int

检查 chars 任意字符是否在 s 中,如果在,则返回对应的下标,不存在或者 chars 为空则返回 -1。该函数将 s 视作 UTF-8 编码的字节切片。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleIndexAny() {
fmt.Println(bytes.IndexAny([]byte("chicken"), "aeiouy"))
fmt.Println(bytes.IndexAny([]byte("crwth"), "aeiouy"))

// Output:
// 2
// -1
}

IndexByte

1
func IndexByte(b []byte, c byte) int

IndexByte 返回字节 c 在字节切片 b 中首次出现的下标,如果 c 不在 b 中返回 -1。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleIndexByte() {
fmt.Println(bytes.IndexByte([]byte("chicken"), byte('k')))
fmt.Println(bytes.IndexByte([]byte("chicken"), byte('g')))

// Output:
// 4
// -1
}

IndexFunc

1
func IndexFunc(s []byte, f func(r rune) bool) int

Index 类似,不过接收一个自定义的回调函数来判断字符是否是满足条件的字符,是则返回 true,这个字符的索引就是 IndexFunc 的返回值。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleIndexFunc() {
f := func(c rune) bool {
return unicode.Is(unicode.Han, c)
}
fmt.Println(bytes.IndexFunc([]byte("Hello, 世界"), f))
fmt.Println(bytes.IndexFunc([]byte("Hello, world"), f))

// Output:
// 7
// -1
}

IndexRune

1
func IndexRune(s []byte, r rune) int

IndexRunes 当作 UTF-8 字节切片,返回 rs 中第一次出现的索引,没有在 s 中则返回 -1。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleIndexRune() {
fmt.Println(bytes.IndexRune([]byte("chicken"), 'k'))
fmt.Println(bytes.IndexRune([]byte("chicken"), 'd'))

// Output:
// 4
// -1
}

Join

1
func Join(s [][]byte, sep []byte) []byte

Join 使用 sep 作为分隔符来连接多个 []byte,返回连接后的结果。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleJoin() {
s := [][]byte{
[]byte("foo"),
[]byte("bar"),
[]byte("baz"),
}
fmt.Printf("%s", bytes.Join(s, []byte(", ")))

// Output:
// foo, bar, baz
}

LastIndex

1
func LastIndex(s, sep []byte) int

LastIndex 返回 seps 中最后出现的索引,没有出现返回 -1。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleLastIndex() {
fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("rodent")))

// Output:
// 0
// 3
// -1
}

LastIndexAny

1
func LastIndexAny(s []byte, chars string) int

IndexAny 类似,但是这个是返回最终出现的位置。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleLastIndexAny() {
fmt.Println(bytes.LastIndexAny([]byte("go gopher"), "MüQp"))
fmt.Println(bytes.LastIndexAny([]byte("go 地鼠"), "地大"))
fmt.Println(bytes.LastIndexAny([]byte("go gopher"), "z,!."))

// Output:
// 5
// 3
// -1
}

LastIndexByte

1
func LastIndexByte(s []byte, c byte) int

LastIndexByte 返回 cs 中最后出现的下标。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleLastIndexByte() {
fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('g')))
fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('r')))
fmt.Println(bytes.LastIndexByte([]byte("go gopher"), byte('z')))

// Output:
// 3
// 8
// -1
}

LastIndexFunc

1
func LastIndexFunc(s []byte, f func(r rune) bool) int

LastIndexFuncIndexFunc 的效果类似,只不过这个是返回最后出现的下标。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleLastIndexFunc() {
fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsLetter))
fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsPunct))
fmt.Println(bytes.LastIndexFunc([]byte("go gopher!"), unicode.IsNumber))

// Output:
// 8
// 9
// -1
}

Map

1
func Map(mapping func(r rune) rune, s []byte) []byte

s 中的每一个字符 c 调用 mapping(c),返回新字符组成的字节切片,如果返回 -1,则返回的结果不包含这个字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleMap() {
rot13 := func(r rune) rune {
switch {
case r >= 'A' && r <= 'Z':
return 'A' + (r - 'A' + 13) % 26
case r >= 'a' && r <= 'z':
return 'a' + (r - 'a' + 13) % 26
}
return r
}

fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher...")))

// Output:
// 'Gjnf oevyyvt naq gur fyvgul tbcure...
}

Repeat

1
func Repeat(b []byte, count int) []byte

Repeat 将一个字节切片 b 重复 count 次,返回最后的结果。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleRepeat() {
fmt.Printf("ba%s", bytes.Repeat([]byte("na"), 2))

// Output:
// banana
}

Replace

1
func Replace(s, old, new []byte, n int) []byte

s 字节切片中的 old 切片替换为 new 切片,最多替换 n 次。如果 n 小于 0,则不限制替换次数。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleReplace() {
fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("k"), []byte("ky"), 2))
fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("oink"), []byte("moo"), -1))

// Output:
// oinky oinky oink
// moo moo moo
}

ReplaceAll

1
func ReplaceAll(s, old, new []byte) []byte

Replace 类似,不过这个是替换所有的 oldnew

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleReplaceAll() {
fmt.Printf("%s\n", bytes.ReplaceAll([]byte("oink oink oink"), []byte("oink"), []byte("moo")))

// Output:
// moo moo moo
}

Runes

1
func Runes(s []byte) []rune

Runes 将字节切片转换为 []byte 类型,s 被视作是 UTF-8 编码的字节切片。

点此查看实例
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 golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleRunes() {
rs := bytes.Runes([]byte("go gopher"))
for _, r := range rs {
fmt.Printf("%#U\n", r)
}

// Output:
// U+0067 'g'
// U+006F 'o'
// U+0020 ' '
// U+0067 'g'
// U+006F 'o'
// U+0070 'p'
// U+0068 'h'
// U+0065 'e'
// U+0072 'r'
}

Split

1
func Split(s, sep []byte) [][]byte

Join 操作相反,根据 sep 来拆分 s

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleSplit() {
fmt.Printf("%q\n", bytes.Split([]byte("a,b,c"), []byte(",")))
fmt.Printf("%q\n", bytes.Split([]byte("a man a plan a cancel panama"), []byte("a ")))
fmt.Printf("%q\n", bytes.Split([]byte(" xyz "), []byte("")))
fmt.Printf("%q\n", bytes.Split([]byte(""), []byte("Bernardo O'Higgins")))

// Output:
// ["a" "b" "c"]
// ["" "man " "plan " "cancel panama"]
// [" " "x" "y" "z" " "]
// [""]
}

SplitAfter

1
func SplitAfter(s, sep []byte) [][]byte

Split 类似,只不过最终结果的每一个字节切片里面包含了分隔符 sep。包含在前一个字节切片中。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleSplitAfter() {
fmt.Printf("%q\n", bytes.SplitAfter([]byte("a,b,c"), []byte(",")))

// Output:
// ["a," "b," "c"]
}

SplitAfterN

1
func SplitAfterN(s, sep []byte, n int) [][]byte

SplitAfter 类似,但是最终返回的 [][]byte 的长度,最多为 n

  • n > 0: 最多返回 n 个子切片,最后一个是剩余的切片

  • n == 0: 返回 nil(0 个子切片)

  • n < 0: 返回所有子切片

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleSplitAfterN() {
fmt.Printf("%q\n", bytes.SplitAfterN([]byte("a,b,c"), []byte(","), 2))

// Output:
// ["a," "b,c"]
}

SplitN

1
func SplitN(s, sep []byte, n int) [][]byte

SplitAfterN 类似,但是这个函数返回的子切片不包含分割符号(除了最后一个有可能包含)。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleSplitN() {
fmt.Printf("%q\n", bytes.SplitN([]byte("a,b,c"), []byte(","), 2))
z := bytes.SplitN([]byte("a,b,c"), []byte(","), 0)
fmt.Printf("%q (nil = %v)\n", z, z == nil)

// Output:
// ["a" "b,c"]
//[] (nil = true)
}

Title

1
func Title(s []byte) []byte

将字节切片转换为标题格式(每个单词改成大写)。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTitle() {
fmt.Printf("%s", bytes.Title([]byte("her royal highness")))

// Output:
// Her Royal Highness
}

ToLower

1
func ToLower(s []byte) []byte

返回一个新的字节切片,所有的 Unicode 字符被转换为小写格式。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleToLower() {
fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))

// Output:
// gopher
}

ToLowerSpecial

1
func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte

第一个参数是指定不同语言的大小写的,有可能某些语言的大小写和英语不太一样,其他和 ToLower 类似。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleToLowerSpecial() {
str := []byte("AHOJ VÝVOJÁRİ GOLANG")
totitle := bytes.ToLowerSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToLower : " + string(totitle))

// Output:
// Original : AHOJ VÝVOJÁRİ GOLANG
// ToLower : ahoj vývojári golang
}

ToTitle

1
func ToTitle(s []byte) []byte

ToTitles 视为 UTF-8 编码的字节,并返回一个副本,其中所有 Unicode 字母都映射到其标题大小写。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleToTitle() {
fmt.Printf("%s\n", bytes.ToTitle([]byte("loud noises")))
fmt.Printf("%s\n", bytes.ToTitle([]byte("хлеб")))

// Output:
// LOUD NOISES
// ХЛЕБ
}

ToTitleSpecial

1
func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte

ToTitleSpecials 视为 UTF-8 编码的字节,并返回一个副本,其中所有 Unicode 字母均映射到其标题大小写,并优先使用特殊的大小写规则。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleToTitleSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToTitleSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToTitle : " + string(totitle))

// Output:
// Original : ahoj vývojári golang
// ToTitle : AHOJ VÝVOJÁRİ GOLANG
}

ToUpper

1
func ToUpper(s []byte) []byte

ToUpper 返回字节片 s 的副本,其中所有 Unicode 字母都映射到其大写字母。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleToUpper() {
fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))

// Output:
// GOPHER
}

ToUpperSpecial

1
func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte

ToUpperSpecials 视为 UTF-8 编码的字节,并返回一个副本,其中所有 Unicode 字母均映射为它们的大写字母,优先考虑特殊的大小写规则。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleToUpperSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
fmt.Println("Origin : " + string(str))
fmt.Println("ToUpper : " + string(totitle))

// Output:
// Origin : ahoj vývojári golang
// ToUpper : AHOJ VÝVOJÁRİ GOLANG
}

ToValidUTF8

1
func ToValidUTF8(s, replacement []byte) []byte

ToValidUTF8s 视为 UTF-8 编码的字节,并返回一个副本,将其中无效的 UTF-8 替换为 replacementreplacement 可以为空。

Trim

1
func Trim(s []byte, cutset string) []byte

Trim 去除 s 前后 cutset 字符串里的子字符,返回最后的结果。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTrim() {
fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!!"), "! "))

// Output:
// ["Achtung! Achtung"]
}

TrimFunc

1
func TrimFunc(s []byte, f func(r rune) bool) []byte

Trim 类似,只不过可以通过回调来筛选。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleTrimFunc() {
fmt.Println(string(bytes.TrimFunc([]byte("go-gopher!"), unicode.IsLetter)))
fmt.Println(string(bytes.TrimFunc([]byte("\"go-gopher!\""), unicode.IsLetter)))
fmt.Println(string(bytes.TrimFunc([]byte("go-gopher!"), unicode.IsPunct)))
fmt.Println(string(bytes.TrimFunc([]byte("1234go-gopher!567"), unicode.IsNumber)))

// Output:
// -gopher!
// "go-gopher!"
// go-gopher
// go-gopher!
}

TrimLeft

1
func TrimLeft(s []byte, cutset string) []byte

Trim 类似,但是只移除 s 左边的字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTrimLeft() {
fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789")))

// Output:
// gopher8257
}

TrimLeftFunc

1
func TrimLeftFunc(s []byte, f func(r rune) bool) []byte

TrimLeft 类似,但是可以通过回调筛选需要移除的字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleTrimLeftFunc() {
fmt.Println(string(bytes.TrimLeftFunc([]byte("go-gopher"), unicode.IsLetter)))
fmt.Println(string(bytes.TrimLeftFunc([]byte(".go-gopher!"), unicode.IsPunct)))
fmt.Println(string(bytes.TrimLeftFunc([]byte("1234go-gopher!567"), unicode.IsNumber)))

// Output:
// -gopher
// go-gopher!
// go-gopher!567
}

TrimPrefix

1
func TrimPrefix(s, prefix []byte) []byte

Trim 类似,但是是移除 prefix 指定的前缀。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTrimPrefix() {
var b = []byte("Goodbye,, world!")
b = bytes.TrimPrefix(b, []byte("Goodbye,"))
b = bytes.TrimPrefix(b, []byte("See ya,"))
fmt.Printf("Hello%s", b)

// Output:
// Hello, world!
}

TrimRight

1
func TrimRight(s []byte, cutset string) []byte

TrimLeft 类似,只不过是移除 s 末尾的字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTrimRight() {
fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789")))

// Output:
// 453gopher
}

TrimRightFunc

1
func TrimRightFunc(s []byte, f func(r rune) bool) []byte

TrimRight 类似,只不过可以接收一个回调来筛选需要移除的字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"fmt"
"unicode"
)

func ExampleTrimRightFunc() {
fmt.Println(string(bytes.TrimRightFunc([]byte("go-gopher"), unicode.IsLetter)))
fmt.Println(string(bytes.TrimRightFunc([]byte("go-gopher!"), unicode.IsPunct)))
fmt.Println(string(bytes.TrimRightFunc([]byte("1234go-gopher!567"), unicode.IsNumber)))

// Output:
// go-
// go-gopher
// 1234go-gopher!
}

TrimSpace

1
func TrimSpace(s []byte) []byte

移除字节切片 s 前后的空白字符。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleTrimSpace() {
fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))

// Output:
// a lone gopher
}

TrimSuffix

1
func TrimSuffix(s, suffix []byte) []byte

移除字节切片 s 的后缀。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"os"
)

func ExampleTrimSuffix() {
var b = []byte("Hello, goodbye, etc!")
b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
b = bytes.TrimSuffix(b, []byte("gopher"))
b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
os.Stdout.Write(b)

// Output:
// Hello, world!
}

Buffer

一个 Buffer 是一个大小不固定的字节缓冲区。Buffer 的零值是一个空的缓冲区。

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package golang_bytes_package_example

import (
"bytes"
"fmt"
"os"
)

func ExampleBuffer() {
var b bytes.Buffer // 不需要初始化
b.Write([]byte("Hello "))
fmt.Fprintf(&b, "world!")
b.WriteTo(os.Stdout)

// Output:
// Hello world!
}
点此查看实例(Reader)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package golang_bytes_package_example

import (
"bytes"
"encoding/base64"
"io"
"os"
)

func ExampleBuffer1() {
// A Buffer can turn a string or a []byte into an io.Reader.
buf := bytes.NewBufferString("R29waGVycyBydWxlIQ==")
dec := base64.NewDecoder(base64.StdEncoding, buf)
io.Copy(os.Stdout, dec)

// Output:
// Gophers rule!
}

NewBuffer

1
func NewBuffer(buf []byte) *Buffer

NewBuffer 使用 buf 作为其初始内容创建并初始化一个新的 Buffer。 新的 Buffer 拥有 buf 的所有权,并且在此调用之后,调用方不应使用buf。 NewBuffer 旨在准备一个 Buffer 以读取现有数据。 它也可以用来设置用于写入的内部缓冲区的初始大小。 为此,buf 应该具有所需的容量,但长度为零。

在大多数情况下,new(Buffer)(或仅声明一个 Buffer 变量)足以初始化 Buffer

NewBufferString

1
func NewBufferString(s string) *Buffer

NewBufferString 使用字符串 s 作为其初始内容创建并初始化一个新的 Buffer。目的是准备一个缓冲区以读取现有的字符串。

在大多数情况下,new(Buffer) (或仅声明一个 Buffer 变量) 足以初始化 Buffer

Buffer 方法

Bytes

1
func (b *Buffer) Bytes() []byte

字节返回长度为 b.Len() 的切片,其中包含缓冲区的未读部分。 该片仅在下一次修改缓冲区之前有效(即,仅在下一次调用诸如 ReadWriteResetTruncate 之类的方法之前)才有效。 切片至少在下一次缓冲区修改之前就将缓冲区内容作为别名,因此对切片的立即更改将影响将来读取的结果。

Cap

1
func (b *Buffer) Cap() int

Cap 返回缓冲区底层字节切片的容量,即为缓冲区数据分配的总空间。

Grow

1
func (b *Buffer) Grow(n int)

如有必要,可以增加缓冲区的容量,以保证另外 n 个字节的空间。在 Grow(n) 之后,至少可以将 n 个字节写入缓冲区,而无需进行其他分配。如果 n 为负数,Grow 会 panic。如果缓冲区无法增长,会引起一个 ErrTooLarge 的 panic。

Len

1
func (b *Buffer) Len() int

Len 返回缓冲区未读部分的字节数;b.Len() == len(b.Bytes())

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleBufferLen() {
var b bytes.Buffer
b.Grow(64)
b.Write([]byte("abcde"))
fmt.Printf("%d", b.Len())

// Output:
// 5
}

Next

1
func (b *Buffer) Next(n int) []byte

Next 返回一个包含缓冲区中接下来 n 个字节的切片,使缓冲区前进,就好像该字节已由 Read 返回。如果缓冲区中的字节数少于 n 个,则 Next 返回整个缓冲区。切片仅在下一次调用 readwrite 方法之前才有效。

Read

1
func (b *Buffer) Read(p []byte) (n int, err error)

Read 从缓冲区中读取下一个 len(p) 字节,或者直到缓冲区耗尽为止。返回值 n 是读取的字节数。如果缓冲区没有数据要返回,则 errio.EOF(除非 len(p) 为 0);否则为零。

ReadByte

1
func (b *Buffer) ReadByte() (byte, error)

ReadByte 读取并从缓冲区返回下一个字节。如果没有可用的字节,则返回错误 io.EOF

ReadBytes

1
func (b *Buffer) Readbytes(delim byte) (line []byte, err error)

ReadBytes 读取直到输入中第一次出现 delim 为止,并返回一个包含数据的切片,该数据直到并包括 delim。如果 ReadBytes 在找到定界符之前遇到错误,它将返回错误之前读取的数据和错误本身(通常为 io.EOF)。并且仅当返回的数据未以 delim 结尾时,ReadBytes 返回 err != nil

ReadFrom

1
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)

ReadFromr 读取数据,直到 EOF 并将其附加到缓冲区,然后根据需要增大缓冲区。返回值 n 是读取的字节数。读取期间遇到的除 io.EOF 以外的任何错误也将返回。如果缓冲区太大,ReadFrom 会引发 ErrTooLarge panic。

ReadRune

1
func (b *Buffer) ReadRune() (r rune, size int, err error)

ReadRune 从缓冲区读取并返回下一个 UTF-8 编码的 Unicode 字符。如果没有可用的字节,则返回的错误是 io.EOF。如果字节是错误的 UTF-8 编码,则它消耗一个字节并返回 U+FFFD,1。

ReadString

1
func (b *Buffer) ReadString(delim type) (line string, err error)

ReadString 读取直到输入中第一次出现 delim 为止,并返回一个字符串,其中包含直到定界符(包括定界符)的数据。如果 ReadString 在找到定界符之前遇到错误,它将返回错误之前读取的数据和错误本身(通常为 io.EOF)。当且仅当返回的数据未以 delim 结尾时,ReadString 才返回 err != nil

Reset

1
func (b *Buffer) Reset()

重置会将缓冲区重置为空,但会保留基础存储空间以供将来的写操作使用。重置与 Truncate(0) 相同。

String

1
func (b *Buffer) String()

String 以字符串形式返回缓冲区未读部分的内容。如果 Buffernil 指针,则返回 ""。

要更有效地构建字符串,请常见 strings.Builder 类型。

Truncate

1
func (b *Buffer) Truncate(n int)

Truncate 会丢弃缓冲区前 n 个未读取字节以外的所有字节,但会继续使用相同的已分配存储。如果 n 为负数或大于缓冲区的长度,则会发生 panic.

UnreadByte

1
func (b *Buffer) UnreadByte() error

UnreadByte 将最近一次成功读取操作的最后一个字节重新设置为未读取。如果自从上次成功读取后有写缓冲区操作,或者上次读取有错误,或者上次读取到 0 字节,UnreadByte 返回一个错误。

UnreadRune

1
func (b *Buffer) UnreadRune() error

UnreadByte 类似,只不过操作的是 rune

Write

1
func (b *Buffer) Write(p []byte) (n int, err error)

写操作会将 p 的内容附加到缓冲区,并根据需要扩展缓冲区。返回值 np 的长度;错误始终为零。如果缓冲区太大,则 Write 会引发 ErrTooLarge panic。

WriteByte

1
func (b *Buffer) WriteByte(c byte) error

写入一个字节到 Buffer。

WriteByte 将字节 c 附加到缓冲区,根据需要增大缓冲区。返回的错误始终为 nil,但包含该错误以匹配 bufio.WriterWriteByte。如果缓冲区太大,WriteByte 会引发 ErrTooLarge panic。

WriteRune

1
func (b *Buffer) WriteRune(r rune) (n int, err error)

ReadRune 类似,不过 WriteRune 是写入一个 rune 类型的数据。

WriteString

1
func (b *Buffer) WriteString(s string) (n int, err error)

写入一个字符串到 Buffer。

WriteStrings 的内容附加到缓冲区,根据需要增大缓冲区。返回值 ns 的长度;错误始终为 nil。如果缓冲区太大,引发 ErrTooLarge panic。

WriteTo

1
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)

WriteTo 将数据写入 w,直到缓冲区耗尽或发生错误。返回值 n 是写入的字节数。它始终适合 int,但与 io.WriterTo 接口匹配为 int64。写入期间遇到的任何错误也将返回。

Reader

Reader 通过读取字节切片来实现 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScannerio.RuneScanner 接口。与 Buffer 不同,Reader 是只读的,并支持查找。Reader 的零值的操作类似空切片的 Reader

NewReader

1
func NewReader(b []byte) *Reader

NewReaderb 返回一个新的 Reader,这个 Reader 将会从 b 读取数据。

Len

1
func (r *Reader) Len() int

Len 返回切片中未读部分的长度

点此查看实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package golang_bytes_package_example

import (
"bytes"
"fmt"
)

func ExampleReaderLen() {
fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())

// Output:
// 3
// 16
}

Read

1
func (r *Reader) Read(b []byte) (n int, err error)

Read 实现了 io.Reader 接口。

ReadAt

1
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)

ReadAt 实现了 io.ReaderAt 接口。

ReadByte

1
func (r *Reader) ReadByte() (byte, error)

ReadByte 实现了 io.ByteReader 接口

ReadRune

1
func (r *Reader) ReadRune() (ch rune, size int, err error)

ReadRune 实现了 io.RuneReader 接口

Reset

1
func (r *Reader) Reset(b []byte)

ResetReader 的内容重置为 b 字节切片。

Seek

1
func (r *Reader) Seek(offset int64, whence int) (int64, error)

Seek 实现了 io.Seeker 接口

Size

1
func (r *Reader) Size() int64

Size 返回了 Reader 底层切片的原始长度。Size 是可通过 ReadAt 读取的字节数。返回的值始终相同,并且不受任何其他方法调用的影响。

UnreadByte

1
func (r *Reader) UnreadByte() error

UnreadByte 在实现 io.ByteScanner 接口时对 ReadByte 进行了补充。

UnreadRune

1
func (r *Reader) UnreadRune() error

UnreadRune 在实现 io.RuneScanner 接口方面对 ReadRune 进行了补充。

WriteTo

1
func (r *Reader) WriteTo(w io.Writer) (n int64, err error)

WriteTo 实现了 io.WriterTo 接口。