The Reader Interface for Go

Purpose: dissect the Reader Interface and learn more.

type Reader interface {
Read(p []byte) (n int, err error)
}

The Reader type below is directly from the documentation and an explanation of how to read it. Its an attempt at trying to visually explain it as well. It's important to know the Reader type and how to read it before you understand how to use its methods. This way you can express it and reuse it as well. This is fundamental to GO. Also, something many people from other languages simply miss.

Reference : https://golang.org/pkg/strings/#NewReader

This part is for glancing and getting an idea of things.

https://golang.org/pkg/io/#Reader

Seems like a lot but do not worry I will break this down.

Explanation: You are using the strings package that has the NewReader method that takes in a string and returns *Reader

The strings.NewReader is important because

now AnotherReader has Read( ) from Diagram 1.1

AnotherReader := strings.NewReader("some string")

But now we need a slice of bytes and we get it by casting []byte (string)

Remember!
type Reader interface {
Read(p []byte) (n int, err error)
}

https://play.golang.org/p/km7-IXuXlu5

Let's utilize that Reader type by looking at the Tour of Go

https://tour.golang.org/methods/21

r := strings.NewReader("Hello, Reader!")
b := make([]byte, 9)
for {
n, err := r.Read(b)
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
if err == io.EOF {
break
}
}

There is a lot going on here from the untrained eye. Go tends to have that effect but you are dealing with some low level stuff too. It's important to understand the low level part of Go to come up with solutions that are built from the ground up. I was once asked why am I going to learn Go? Am I interested in optimizing? I think there is a lot to this language and maybe more so than what is first seen.

Lets try and break down just the 3 lines from above with the below

1. r := strings.NewReader("Hello, Reader!")

Now when we want to use r.Read() we have to remember that r is type *Reader and implements the following.

https://golang.org/pkg/bytes/#NewReader

So the final line is really the final result after those two lines. They dont look like much at first but there is a lot going on. This is the magic of Go in action. You use a few lines that are high level to do low level lifting and put all that into a name r. Go seems to be one big naming game and you have to really work with it to follow the rules but also to construct and appreciate why methods were chosen and what goes into just a single name.

Overview
  1. The io.Reader interface has a Read method.
  2. r is also using the strings package with the NewReader()
  3. r is of type Reader https://golang.org/pkg/io/#Reader
  4. r also has the string “Hello, Reader!”
  5. Read() takes in a []bytes and returns an error and an int
  6. b is a map of []bytes with len
  7. r can use then all those io methods and take in other types from the NewReader’s []bytes

So if we change the len or “9” in the map then we will get a max amount of characters from the string. This might seem like a lot of work to just utilize r and get a length of a string but the point is now you have a name r that has all these methods and types. This is important when building packages and utilizing something that is from the standard package and is built into the language itself. The reason I didn’t list these out at the beginning was to get you to understand how to read from the Go docs. You have to appreciate the architecting of these types and methods. The point is when architecting your own package you have to keep this idea of the importance of naming in your own package. Go is all about names and carefully creating a package that allows for understandability and ease of use and there is a lot of magic architecting behind these names.

type Reader interface {
Read(p []byte) (n int, err error)
}

Again the type Reader doesn’t seem like much but there is so much magic and careful crafting that you really have to start understanding this process. You will be using it to build bigger things. This also becomes important when trying to utilize other packages and dealing with big code bases. You can kinda start to see that implementing these types leads to extending behavior and not affecting original design. This “way” of coding is different in other languages because the languages tend to allow for options that usually sway coders from basing code on types instead of interfaces, if they even go for interfaces to begin with. Usually coding based on explicitly satisfying interfaces or traits tends to make packages really restrictive and hard to reuse. Even though the purpose of using these features is to make something someone can use. As you learn go, this simple design and preference for careful crafting will appear in most scripts.

Will try to implement this in the next article.