I'm trying to understand Go by studying gopl book. I'm stuck when trying to implement the LimitReader
function. I realized that I have two problems so let me separate them.
First issue
The description from official doc is saying that:
A LimitedReader reads from R but limits the amount of data returned to just N bytes. Each call to Read updates N to reflect the new amount remaining. Read returns EOF when N <= 0 or when the underlying R returns EOF.
OK, so my understanding is that I can read from io.Reader
type many times but I will be always limited to N
bytes. Running this code shows me something different:
package main
import (
"fmt"
"io"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
lr := io.LimitReader(r, 4)
b := make([]byte, 7)
n, err := lr.Read(b)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Read %d bytes: %s\n", n, b)
b = make([]byte, 5)
n, _ = lr.Read(b)
// If removed because EOF
fmt.Printf("Read %d bytes: %s\n", n, b)
}
// Output:
// Read 4 bytes: some
// Read 0 bytes:
// I expect next 4 bytes instead
It seems that this type of object is able to read only once. Not quite sure but maybe this line in io.go source code could be changed to l.N = 0
. The main question is why this code is inconsistent with doc description?
Second issue
When I've struggled with the first issue I was trying to display current N
value. If I put fmt.Println(lr.N)
to the code above it cannot be compiled lr.N undefined (type io.Reader has no field or method N)
. I realized that I still don't understand Go interfaces concept.
Here is my POV (based on listing above). Using io.LimitReader
function I create LimitedReader
object (see source code). Due to the fact that this object contains Read
method with proper signature its interface type is io.Reader
. That's is the reason why io.LimitReader
returns io.Reader
, right? OK, so everything works together.
The question is: why lr.N
cannot be accessed? As I correctly understood the book, interface type only requires that data type contains some method(s). Nothing more.
LimitedReader
limits the total size of data that can be read, not the amount of data that can be read at each read call. That is, if you set the limit to 4, you can perform 4 reads of 1 byte, or 1 read of 4 bytes, and after that, all reads will fail.
For your second question: lr
is an io.Reader
, so you cannot read lr.N
. However, you can access the underlying concrete type using a type assertion: lr.(*io.LimitedReader).N
should work.