本文最后由 森林生灵 于 2020/07/04 01:58:54 编辑
golang 的 io.MultiWriter()
函数可以将多个实现 io.Writer
接口实例包装为一个,实现多实例统一写入。但在开发自定义日志库时使用此函数遇到了这样一个问提,传入的多个接口实例总会有几个不会生效,而且好似是否生效还跟入传参位置有关。参考了网络上的案例,测试可以正常工作。
func test() { file, err := os.Create("tmp.txt") if err != nil { panic(err) } defer file.Close() writer := io.MultiWriter(file, os.Stdout) writer.Write([]byte("Hello")) }
有问题的部分代码如下:
// 控制台打印彩色日志 type Console struct {} func (c *Console) Write(p []byte) (n int, err error) { prefix := "" msg := string(p) length := len("[INFO]") if len(msg) >= length { prefix = msg[:length] switch prefix { case "[INFO]": prefix = StringBlue(prefix) case "[WARN]": prefix = StringYellow(prefix) case "[ERRO]": prefix = StringRed(prefix) case "[HTTP]": prefix = StringGreen(prefix) } } if prefix != "" { // 控制台打印彩色字符前缀 return fmt.Fprintln(os.Stdout, prefix, msg[length:]) } else { // 没有前缀直接输出原始消息 return fmt.Fprintln(os.Stdout, msg) } } // 发送严重错误通知 type Logger struct {} func (l *Logger) Write(p []byte) (n int, err error) { // TODO:// file, err := os.Create("tmp.txt") if err != nil { panic(err) } defer file.Close() file.Write(p) // 由于尚未完成的该部分功能,为了测试 io.MultiWriter() 直接返回默认值 return 0, nil } // 测试 io.MultiWriter() func test() { writer := io.MultiWriter(os.Stderr, &console.Console{}, &reporter.Reporter{}) writer.Write([]byte("[INFO]Test Msg")) writer.Write([]byte("Raw Msg")) }
表面看似两段代码没有什么错误,而且还把接口方法返回值的 error
硬性定义为 nil
,但运行起来却大相径庭,经过一番查找发现异常原因在于 io.MultiWriter()
它不仅仅是判断返回值的 error
,还判断返回值的长度是否和传入 []byte
的长度一致。
func (t *multiWriter) Write(p []byte) (n int, err error) { for _, w := range t.writers { n, err = w.Write(p) if err != nil { return } // 处理后的切片长度要与原传入切片的长度一样,否则直接跳出循环,不在执行之后的 io.Write if n != len(p) { err = ErrShortWrite return } } return len(p), nil }
再回头看一下实现的那两个实例,很明显 &console.Console{}
在有符合的 prefix
时会对原始数据进行了修改,返回 fmt.Fprintln()
中的长度固然比原来的长;同时又由于 &reporter.Reporter{}
中强制返回的长度为 0,也会触发错误而终止循环。
心得,在本案例中参考了网传案例,先入为主,并未输出 io.MultiWriter()
的返回值,不曾考虑在 error
为 nil
时亦会导致程序中途跳出,故开发时一定要输出调用函数的返回值,即使上层函数 error
为 nil
,也要输出一下,可(我)以(还)避(是)免(太)走(菜)弯(了)路 .....
本文标题:注意 io.MultiWriter 的返回值
版权声明:本文使用「署名-非商业性使用-相同方式共享」创作共享协议,转载或使用请遵守署名协议。
相关文章
上一篇:golang 模板语法