这一章,继续介绍 go 语言中内置的接口 interface。
在 io 这个包中,定义了 io.Reader 接口,代表读取数据流的功能。
在操作系统中,有大量读操作,例如读文件、网络、压缩包、加密流等等。这些操作都可以抽象为一个 Reader 接口的 Read 方法,只需要不同场景实现相应的逻辑即可,是不是很优雅。这种设计十分符合 unix 操作系统“大道至简”的哲学。
当然,如果最初那帮折腾操作系统的人早早接触我们伟大的“东方哲学”,肯定会更早发现这么简单实用d的抽象逻辑。
Read 的函数签名是:
func (T) Read(b []byte) (n int, err error)
它读取一串字节切片,返回读取到的字节数以及 error 值(不一定是报错)。当读到数据流的末尾时,会返回 io.EOF 报错。
来看下示例代码:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Hello, Reader!") // 初始化 reader
b := make([]byte, 8) // 一次读取8个字节
for {
n, err := r.Read(b) // 调用 Read 读取
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
fmt.Printf("b[:n] = %q\n", b[:n])
if err == io.EOF { // 判断是否读完
break
}
}
}
ok,我们来做个练习,自己实现一个 Read 方法:
package main
type MyReader struct{} // 声明结构体
func (r MyReader) Read(b []byte) (int, error) { // 实现 Read 方法
l := len(b) // 获取字节切片长度
for i := 0; i < l; i ++ {
b[i] = 65 // 赋值 ascii 编码 A
}
return l, nil
}
如上,实现 Read 方法,就实现了自定义逻辑的 Reader 接口。
接着,我们来实现一个破解密码的 Reader,使用的加密算法是“ROT13”,即“回转13位”。就是把每个英语字母都替换为它向后第13位的字母,如果超过26个字母,则从头开始映射,即所谓的“回转”。举个例子,“A”替换为“N”,“B”替换为“O”。“A”是第一个字母,“N”是第14个字母。到了“N”的时候,再替换回“A”。形成这种一一对应的关系。
废话不多说,上代码:
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func (r rot13Reader) Read(b []byte) (int, error) {
b2 := make([]byte, 100) // 定义一个读取用的 byte 切片
n := 0 // 初始化局部变量 n,用来获取字符的个数
for {
n1, err := r.r.Read(b2) // 从属性 r 中读取加密字符串
if err == io.EOF {
break
}
n = n1 // 获得字符串的个数
}
for i := 0; i < n ; i++ { // 遍历所有字符
a := b2[i]
// 进行解密
if (a >= 65 && a <= 90) || (a >= 97 && a <=122) {
a = a - 13
if a < 65 {
a = 90 - (64 - a)
} else if a < 97 {
a = 122 - (96 - a)
}
}
// 赋值到传参 b 中
b[i] = a
}
// 这里偷了懒,其实要判断是否读取完所有字符串
return n, io.EOF
}
func main() {
// 要解密的就是这一串字符
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
ok,这一章先到这里~