该函数将len(p)
写入p
,因此p
在调用之前必须具有一些虚拟内容,并且该内容在调用之后将被覆盖。
如果这种理解是正确的,那么为什么函数不使用并检查cap(p)
呢?
谢谢。
最佳答案
Read
方法的任务只是将len(p)
字节读取到基础数组中,并返回读取的字节数和错误。因此,它与cap(p)
无关。
来自
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
表示p
是byte
的一部分,因此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
}
所采用方法的另一个好处是,您可以分配一个大的支持数组,即
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/