为何说strings.Reader类型的值能够高效地读取字符串ui
与strings.Builder类型偏偏相反,strings.Reader类型是为了高效读取字符串而存在的。后者的高效主要体如今它对字符串的读取机制上,它封装了不少用于在string值上读取内容的最佳实践。spa
strings.Reader类型的值(如下简称Reader值)可让咱们很方便地读取一个字符串中的内容。在读取的过程当中,Reader值会保存已读取的字节的计数(如下简称已读计数)。code
已读计数也表明着下一次读取的起始索引位置。Reader值正是依靠这样一个计数,以及针对字符串值的切片表达式,从而实现快速读取。blog
此外,这个已读计数也是读取回退和位置设定时的重要依据。虽然它属于Reader值的内部结构,但咱们仍是能够经过该值的Len方法和Size把它计算出来的索引
Reader值拥有的大部分用于读取的方法都会及时地更新已读计数。好比,ReadByte方法会在读取成功后将这个计数的值加1。ci
又好比,ReadRune方法在读取成功以后,会把被读取的字符所占用的字节数做为计数的增量。字符串
不过,ReadAt方法算是一个例外。它既不会依据已读计数进行读取,也不会在读取后更新它。正由于如此,这个方法能够自由地读取其所属的Reader值中的任何内容。string
// 示例1。 reader1 := strings.NewReader( "中文的的的SimpleNewReader returns a new Reader reading from s. " + "It is similar to bytes.NewBufferString but more efficient and read-only. ") %d\n",reader1.Size()-int64(reader1.Len())) fmt.Printf("len:%d\n",reader1.Len()) //原始字符串长度是141 by:= make([]byte,20) reader1.ReadAt(by,2) //这个方法不作计数也就是原值不变也就是len长度仍是原始长度 buf1 := make([]byte, 3) //原值偏移量+3 len长度要-3 reader1.Read(buf1) fmt.Printf("len:%d value:%s\n",reader1.Len(),string(buf1))
打印结果为it
len:141
len:138 value:中 io
除此以外,Reader值的Seek方法也会更新该值的已读计数。实际上,这个Seek方法的主要做用正是设定下一次读取的起始索引位置
offset2 := int64(17) expectedIndex := reader1.Size() - int64(reader1.Len()) + offset2 fmt.Printf("Seek with offset %d and whence %d ...\n", offset2, io.SeekCurrent) readingIndex, _ := reader1.Seek(offset2, io.SeekCurrent) fmt.Printf("The reading index in reader: %d (returned by Seek)\n", readingIndex) fmt.Printf("The reading index in reader: %d (computed by me)\n", expectedIndex)