长安链 DApp 开发必学 Go 13

125 阅读2分钟

这一章,继续介绍 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,这一章先到这里~