go - 为什么标准库bufio.Read(p [] byte)(int,err)在Go中检查len(p)而不是cap(p)

标签 go

该函数将len(p)写入p,因此p在调用之前必须具有一些虚拟内容,并且该内容在调用之后将被覆盖。
如果这种理解是正确的,那么为什么函数不使用并检查cap(p)呢?
谢谢。

最佳答案

Read方法的任务只是将len(p)字节读取到基础数组中,并返回读取的字节数和错误。因此,它与cap(p)无关。

  • TLDR:设计为 (字节是从底层Reader上的最多Read读取的):
    来自go/src/bufio/bufio.go:
  • // Read reads data into p.
    // It returns the number of bytes read into p.
    // The bytes are taken from at most one Read on the underlying Reader,
    // hence n may be less than len(p).
    // To read exactly len(p) bytes, use io.ReadFull(b, p).
    // At EOF, the count will be zero and err will be io.EOF.
    func (b *Reader) Read(p []byte) (n int, err error) {
    
    是的,可以使用cap(p),而不是cap(p)来读取len(p),但这是另一种设计选择,它具有权衡(例如:对于重新 slice ,您可能需要为每个对象使用内存分配和每次调用),由于它返回读取的字节数,因此调用方可以使用重新分片将所需的长度发送给Read方法。 Try it:
    package main
    
    import "fmt"
    
    func main() {
        p := make([]byte, 0, 4)
        n := read(p)
        p = p[:n]
        fmt.Println(len(p), cap(p)) // 4 4
        fmt.Println(p)              // [0 0 0 4]
    }
    func read(p []byte) int {
        n := cap(p)
        p = p[:n]
        p[n-1] = 4
        return n
    }
    
  • p是一个 slice ,并通过值传递,并且Read方法可以不能而不是更改p长度容量,并将该方法内部的方法发送回外界(签名到Read(p *[]byte)Read(p []byte) []byte)。
    func (b *Reader) Read(p []byte) (n int, err error) {p []byte表示pbyte的一部分,因此p本身是一种数据结构,其中包含指向基础数组的指针以及该数组的长度和容量。
    不允许使用此方法更改p容量长度,假设p的长度为0,则需要将其更改为4(请参阅this QA)。由于方法外部的p是与方法内部的p不同的变量,请尝试this,请参见输出(请参见注释)。 p地址内部是0xc00000c080,外部是0xc00000c060-因此它是一个不同的变量):
  • package main
    
    import "fmt"
    
    func main() {
        p := make([]byte, 0, 4)
        fmt.Println(len(p), cap(p)) // 0 4
        fmt.Printf("%p\n", &p)      // 0xc00000c060
    
        read(p)
    
        fmt.Println(len(p), cap(p)) // 0 4
        fmt.Printf("%p\n", &p)      // 0xc00000c060
    
        fmt.Println(p)
    }
    func read(p []byte) {
        fmt.Println(len(p), cap(p)) // 0 4
        fmt.Printf("%p\n", &p)      // 0xc00000c080
        p = p[:cap(p)]
        fmt.Println(len(p), cap(p)) // 4 4
        fmt.Println(p)              // [0 0 0 0]
        fmt.Printf("%p\n", &p)      // 0xc00000c080
    }
    
    
  • 感谢@Brits:
    所采用方法的另一个好处是,您可以分配一个大的支持数组,即a := make([]byte,0,BIGSIZE),然后在多次调用Read中使用一个缓冲区,而无需重新分配(n, _ := read(a[0:4]n,_ = read(a[n:n+2])。如果Read确实使用了容量,则需要为每个调用分配一个精确大小的缓冲区。
  • 关于go - 为什么标准库bufio.Read(p [] byte)(int,err)在Go中检查len(p)而不是cap(p),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63095490/

    相关文章:

    go - 将数据库行读入 map 并附加到 map slice

    image - 在Golang中检查HEIC文件格式

    html - Go r.FormValue 为空

    sql - 是否可以在执行查询时传入参数数组而不是单独传递每个参数?

    go - 使用 Gmail API 检索邮件正文

    go - path.join上升两个目录

    go - 在 Golang 中将 GDI32.dll 位图保存到磁盘

    go-lang项目文件夹结构约定

    struct - 高语 : Variable length array in struct for use with binary read

    GoRoutines 并将结构传递给原始上下文