// new reader返回从s读取的新reader。
//类似bytes。新的缓冲区字符串,但更有效和不可写。
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
// A Reader implements the io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner,io.RuneReader, io.RuneScanner, io.Seeker, and io.WriterTo interfaces by reading from a string.
// The zero value for Reader operates like a Reader of an empty string.
type Reader struct {
s string //表示 Reader 要读取的数据源。
i int64 // 一个整数,表示当前读取的索引位置。
prevRune int // 一个整数,表示上一个读取的符文的索引位置,如果没有读取过符文,则为负数。
}
func (r *Reader) Len() int {
if r.i >= int64(len(r.s)) {
return 0
}
return int(int64(len(r.s)) - r.i)
}
// Size returns the original length of the underlying string.
// Size is the number of bytes available for reading via ReadAt.
// The returned value is always the same and is not affected by calls
// to any other method.
func (r *Reader) Size() int64 { return int64(len(r.s)) }
// Read 实现 the io.Reader 接口.
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
//如果当前读取索引 r.i 大于或等于字符串 r.s 的长度,说明已经到达字符串末尾,返回 0 和 io.EOF 错误,表示没有更多数据可读。
//io.go声明
//var EOF = errors.New("EOF")
//n = copy(b, r.s[r.i:]):这行代码使用 copy 函数将字符串 r.s 从当前索引 r.i 开始的部分复制到字节切片 b 中,并将实际复制的字节数赋给变量 n。
//r.i += int64(n):这行代码将当前读取索引 r.i 向前移动 n 个字节,以便下次读取时从新的位置开始。
//return:最后,方法返回读取的字节数 n 和错误 err(如果有)。
r.prevRune
字段在 strings.Reader
结构体中用于记录上一个读取的 rune
(Unicode字符)的索引。这个字段在不同的方法中有不同的使用情况:
-
使用时机:
- 当使用
ReadRune
方法时,prevRune
字段会被使用。ReadRune
方法用于读取字符串中的下一个rune
,并返回它以及它的大小(以字节为单位)。在这种情况下,prevRune
用于记录上一个读取的rune
的索引,以便在下一次调用ReadRune
时能够正确地继续读取。
- 当使用
-
未使用时:
- 当使用
Read
方法时,prevRune
字段不会被使用。Read
方法用于从strings.Reader
指向的字符串中读取数据到提供的字节切片中。由于Read
方法是基于字节的读取,而不是基于rune
的读取,因此不需要记录上一个读取的rune
的索引。这就是为什么在Read
方法的开始,prevRune
被设置为-1
,表示它在这个方法中不会被使用。
- 当使用
使用样例
//从字符串中读取内容
str1Reader := strings.NewReader("hello")
bytes,_:=io.ReadAll(str1Reader)
print(string(bytes))
io.ReadAll
func ReadAll(r Reader) ([]byte, error) {
b := make([]byte, 0, 512)
for {
n, err := r.Read(b[len(b):cap(b)])
b = b[:len(b)+n]
if err != nil {
if err == EOF {
err = nil
}
return b, err
}
if len(b) == cap(b) {
// Add more capacity (let append pick how much).
b = append(b, 0)[:len(b)]
}
}
}
//Reader使用一个借口类型 只有重载了Read方法就能调用
type Reader interface {
Read(p []byte) (n int, err error)
}
// ReadRune implements the io.RuneReader interface.
func (r *Reader) ReadRune() (ch rune, size int, err error) {
if r.i >= int64(len(r.s)) {
r.prevRune = -1
return 0, 0, io.EOF
}
r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRuneInString(r.s[r.i:])
r.i += int64(size)
return
}
-
func (r *Reader) ReadRune() (ch rune, size int, err error) {
:这是方法的声明。ReadRune
方法返回三个值:读取的符文ch
、符文的字节大小size
和可能的错误err
。 -
if r.i >= int64(len(r.s)) {... }
:这是一个条件判断,如果当前读取索引r.i
大于或等于字符串r.s
的长度,说明已经到达字符串末尾,返回 0、0 和io.EOF
错误,表示没有更多数据可读。 -
r.prevRune = int(r.i)
:这行代码将prevRune
设置为当前读取索引r.i
的整数值。 -
if c := r.s[r.i]; c < utf8.RuneSelf {... }
:这是一个条件判断,如果当前字符c
的值小于utf8.RuneSelf
(即 128),说明它是一个 ASCII 字符,可以直接读取。 -
r.i++
:这行代码将当前读取索引r.i
向前移动一个字节。 -
return rune(c), 1, nil
:这行代码返回读取的字符c
作为符文,字节大小为 1,并且没有错误。 -
ch, size = utf8.DecodeRuneInString(r.s[r.i:])
:如果当前字符不是 ASCII 字符,这行代码使用utf8.DecodeRuneInString
函数从字符串r.s
中当前索引r.i
开始的部分解码一个符文,并将符文和字节大小分别赋给变量ch
和size
。 -
r.i += int64(size)
:这行代码将当前读取索引r.i
向前移动size
个字节,以便下次读取时从新的位置开始。 -
return ch, size, nil
:最后,方法返回读取的符文ch
、字节大小size
和没有错误。
总的来说,这个方法的作用是从字符串中读取一个 UTF-8 编码的符文,并返回符文的值、字节大小和是否发生错误。如果没有更多数据可读,它会返回 io.EOF
错误。