為什么說strings.Reader類型的值可以高效地讀取字符串
與strings.Builder類型恰恰相反,strings.Reader類型是為了高效讀取字符串而存在的。后者的高效主要體現在它對字符串的讀取機制上,它封裝了很多用於在string值上讀取內容的最佳實踐。
strings.Reader類型的值(以下簡稱Reader值)可以讓我們很方便地讀取一個字符串中的內容。在讀取的過程中,Reader值會保存已讀取的字節的計數(以下簡稱已讀計數)。
已讀計數也代表着下一次讀取的起始索引位置。Reader值正是依靠這樣一個計數,以及針對字符串值的切片表達式,從而實現快速讀取。
此外,這個已讀計數也是讀取回退和位置設定時的重要依據。雖然它屬於Reader值的內部結構,但我們還是可以通過該值的Len方法和Size把它計算出來的
Reader值擁有的大部分用於讀取的方法都會及時地更新已讀計數。比如,ReadByte方法會在讀取成功后將這個計數的值加1。
又比如,ReadRune方法在讀取成功之后,會把被讀取的字符所占用的字節數作為計數的增量。
不過,ReadAt方法算是一個例外。它既不會依據已讀計數進行讀取,也不會在讀取后更新它。正因為如此,這個方法可以自由地讀取其所屬的Reader值中的任何內容。
// 示例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))
打印結果為
len:141
len:138 value:中
除此之外,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)