一文了解io包中的discard类型
1. 引言
io.discard是Go语言标准库提供一个结构体类型,其在丢弃不需要的数据场景下非常好用。本文我们将从io.discard 类型的基本定义出发,讲述其基本使用和实现原理,接着简单描述 io.discard 的使用场景,基于此完成对 io.discard 类型的介绍。
2. 介绍
2.1 基本定义
io.discard 是 Go语言提供的一个Writer,这个Writer 比较特殊,其不会做任何事情。它会将写入的数据立即丢弃,不会做任何处理。其定义如下:
type discard struct{}
func (discard) Write(p []byte) (int, error) {}
func (discard) WriteString(s string) (int, error) {}
func (discard) ReadFrom(r Reader) (n int64, err error) {}
discard 结构体类型没有定义任何字段,同时还提供了Write ,ReadFrom和WriteString 方法,Write 方法和WriteString 方法分别接收字节切片和字符串,然后返回写入的字节数。
同时还实现了io.ReaderFrom 接口,这个是为了在使用 io.Copy 函数时,将数据从源复制到io.discard 时,避免不必要的操作。
从上面discard 的定义可以看起来,其不是一个公开类型的结构体类型,所以我们并不能创建结构体实例。事实上Go语言提供了一个io.discard 实例的预定义常量,我们直接使用,无需自己创建实例,定义如下:
var Discard Writer = discard{}
2.2 使用说明
下面通过一个丢弃网络连接中不再需要的数据的例子,来展示io.Discard 的使用,代码示例如下:
package main
import (
"fmt"
"io"
"net"
"os"
)
func discardData(conn net.Conn, bytesToDiscard int64) error {
_, err := io.CopyN(io.Discard, conn, bytesToDiscard)
return err
}
func main() {
conn, err := net.Dial("tcp", "example.com:80")
if err != nil {
fmt.Println("连接错误:", err)
return
}
defer conn.Close()
bytesToDiscard := int64(1024) // 要丢弃的字节数
err = discardData(conn, bytesToDiscard)
if err != nil {
fmt.Println("丢弃数据错误:", err)
return
}
fmt.Println("数据已成功丢弃。")
}
在上面示例中,我们建立了网络连接,然后连接中的前1024个字节的数据是不需要的。这个时候,我们通过io.CopyN 函数将数据从conn 拷贝到io.Discard 当中,基于io.Discard 丢弃数据的特性,成功将连接的前1024个字节丢弃掉,而不需要自定义缓冲区之类的操作,简单高效。
3. 实现原理
io.Discard的目的是在某些场景下提供一个满足io.Writer接口的实例,但用户对于数据的写入操作并不关心。它可以被用作一个黑洞般的写入目标,默默地丢弃所有写入它的数据。所以io.discard 的实现也相对比较简单,不对输入的数据进行任何处理即可,下面我们来看具体的实现。
首先是io.discard 结构体的定义,没有定义任何字段,因为本来也不需要执行任何写入操作:
type discard struct{}
而对于Write 和 WriteString 方法,其直接返回了传入参数的长度,往该Writer 写入的数据不会被写入到其他地方,而是被直接丢弃:
func (discard) Write(p []byte) (int, error) {
return len(p), nil
}
func (discard) WriteString(s string) (int, error) {
return len(s), nil
}
同时discard 也实现了io.ReaderFrom 接口,实现了ReadFrom 方法,实现也是非常简单,从blackHolePool 缓冲池中获取字节切片,然后不断读取数据,读取完成之后,再将字节切片重新放入缓冲池当中:
// 存在一个字节切片缓冲池
var blackHolePool = sync.Pool{
New: func() any {
b := make([]byte, 8192)
return &b
},
}
func (discard) ReadFrom(r Reader) (n int64, err error) {
// 从缓冲池中取出一个 字节切片
bufp := blackHolePool.Get().(*[]byte)
readSize := 0
for {
// 不断读取数据,bufp 只是作为一个读取数据的中介,读取到的数据并无意义
readSize, err = r.Read(*bufp)
n += int64(readSize)
if err != nil {
// 将字节切片 重新放入到 blackHolePool 当中
blackHolePool.Put(bufp)
if err == EOF {
return n, nil
}
return
}
}
}
在io.Copy 函数中,将调用discard 中的ReadFrom 方法,能够将Writer中的所有数据读取完,然后丢弃掉。
4. 使用场景
io.Discard 给我们提供了一个io.Writer 接口的实例,同时其又不会真实得写入数据,这个在某些场景下非常有用。
有时候,我们可能需要一个实现io.Writer 接口的实例,但是我们并不关心数据写入Writer 的结果,也不关心数据是否写到了哪个地方,此时io.Discard 就给我们提供了一个方便的解决方案。同时io.Discard 可以作为一个黑洞写入目标,能够将数据默默丢弃掉,不会进行实际的处理和存储。
所以如果我们想要丢弃某些数据,亦或者是需要一个io.Writer接口的实例,但是对于写入结果不需要关注时,此时使用io.Discard 是非常合适的。
5. 总结
io.discard 函数是Go语言标准库中一个实现了Writer接口的结构体类型,能够悄无声息得实现数据的丢弃。 我们先从io.discard 类型的基本定义出发,之后通过一个简单的示例,展示如何使用io.discard 类型实现对不需要数据的丢弃。
接着我们讲述了io.discard 类型的实现原理,其实就是不对写入的数据执行任何操作。在使用场景下,我们想要丢弃某些数据,亦或者是需要一个io.Writer接口的实例,但是对于写入结果不需要关注时,此时使用io.Discard 是非常合适的。
基于此,便完成了对io.discard 类型的介绍,希望对你有所帮助。
一文了解io包中的discard类型的更多相关文章
- java.io包中的字节流—— FilterInputStream和FilterOutputStream
接着上篇文章,本篇继续说java.io包中的字节流.按照前篇文章所说,java.io包中的字节流中的类关系有用到GoF<设计模式>中的装饰者模式,而这正体现在FilterInputStre ...
- 黑马程序员——【Java基础】——File类、Properties集合、IO包中的其他类
---------- android培训.java培训.期待与您交流! ---------- 一.File类 (一)概述 1.File类:文件和目录路径名的抽象表现形式 2.作用: (1)用来将文件或 ...
- 1.java.io包中定义了多个流类型来实现输入和输出功能,
1.java.io包中定义了多个流类型来实现输入和输出功能,可以从不同的角度对其进行分 类,按功能分为:(C),如果为读取的内容进行处理后再输出,需要使用下列哪种流?(G) A.输入流和输出流 B ...
- 字节输入流:io包中的InputStream为所有字节输入流的父类。
字节输入流:io包中的InputStream为所有字节输入流的父类. Int read();读入一个字节(每次一个): 可先使用new byte[]=数组,调用read(byte[] b) read ...
- Java之IO(十四)IO包中其它类
转载请注明出处:http://www.cnblogs.com/lighten/p/7267553.html 1.前言 此章介绍IO包中剩余未介绍的几个流和工具类,包括LineNumberReader. ...
- IO包中的其他类
查看各对象API文档 打印流 PrintWriter PrintStream 序列流:对多个流进行排列合并 SequenceInputStream public static void main(St ...
- Java基础---IO(三)--IO包中的其他类
第一讲 对象序列化 一.概述 将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化).使用到的两个类:ObjectInputStream和ObjectOutputStrea ...
- IO包中的RandomAccessFile类
RandomAccessFile RandomAccessFile 是随机访问文件的类.它支持对文件随机访问的读取和写入,即我们也可以从指定的位置读取/写入文件数据,因为该类在其内部封装了一个数组和指 ...
- Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题
PrintWriter打印流 Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便 同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法 ...
- IO包中的其他类总结
一.PrintStream和PrintWriter PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式. PrintStream 打印的所有字符都使用平台的默认字符 ...
随机推荐
- 最新版本 Stable Diffusion 开源 AI 绘画工具之图生图进阶篇
目录 图生图基本参数 图生图(img2img) 涂鸦绘制(Sketch) 局部绘制(Inpaint) 涂鸦蒙版(Inpaint sketch) 上传蒙版(Inpaint upload) 图生图基本参数 ...
- java.lang.OutOfMemoryError- unable to create new native thread 问题排查
问题描述 最近连续两天大约凌晨3点,线上服务开始异常,出现OOM报错.且服务所在的物理机只能ping通,但是无法登录.报错信息如下: ERROR 04-12 03:01:43,930 [Default ...
- MySQL(九)InnoDB数据结构
InnoDB数据结构 1 数据库的存储结构:页 索引信息和数据记录都是保存在文件上的,确切来说是保存在页结构中:另一方面,索引是在存储引擎上实现的,MySQL服务器上的存储引擎负责对表中数据的读取 ...
- 【Vue2.x源码系列06】计算属性computed原理
上一章 Vue2异步更新和nextTick原理,我们介绍了 JavaScript 执行机制是什么?nextTick源码是如何实现的?以及Vue是如何异步更新渲染的? 本章目标 计算属性是如何实现的? ...
- Rainbond 结合 Jpom 实现云原生 & 本地一体化项目管理
Jpom 是一个简而轻的低侵入式在线构建.自动部署.日常运维.项目运维监控软件.提供了: 节点管理:集群节点,统一管理多节点的项目,实现快速一键分发项目文件 项目管理:创建.启动.停止.实时查看项目控 ...
- P1350 车的放置 题解
一.题目描述: 给你一个网格棋盘,a,b,c,d 表示了对应边长度,也就是对应格子数. 例如,当 a=b=c=d=2 时,对应了下面这样一个棋盘: 想要在这个棋盘上放 k 棋子,也就是这 k 个棋子没 ...
- Stream方法的介绍
文章目录 前言 Lambda表达式 格式 函数式接口 Stream的方法介绍 forEach filter collect count sum limit 和skip groupingBy reduc ...
- IPS 和 IDS
IPS/IDS 什么是IPS和IDS IDS/IPS是检测和防止对网络服务器进行未授权的访问的系统.有许多产品同时有IDS和IPS的作用,作为加强企业信息安全所必须的系统 什么是IDS(Intrusi ...
- 2022-06-28:以下golang代码输出什么?A:true;B:false;C:panic;D:编译失败。 package main import “fmt“ func main() {
2022-06-28:以下golang代码输出什么?A:true:B:false:C:panic:D:编译失败. package main import "fmt" func ma ...
- SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析
系列文章目录和关于我 零丶引入 我在初学spring的时候,很懵逼,因为整个项目中不存在main方法,让我有点摸不着头脑.那时候我知道有个东西叫tomcat是它监听了端口,解析了协议调到了我的serv ...