- Learning Functional Programming in Go
- Lex Sheehan
- 477字
- 2025-02-27 05:14:35
Using the Reader and Writer interfaces
Let's exercise what we've learned about the io.Reader and io.Writer interfaces:
package main
import (
"io"
"strings"
"os"
)
type titlizeReader struct {
src io.Reader
}
func NewTitlizeReader(source io.Reader) *titlizeReader {
return &titlizeReader{source}
}
Recall that the Reader interface looks like this:
type Reader interface {
Read(p []byte) (n int, err error)
}
When we implement the Read method, our titlizeReader struct now satisfies the Reader interface:
func (t *titlizeReader) Read(p []byte) (int, error) {
count, err := t.src.Read(p)
if err != nil {
return count, err
} for i := 0; i < len(p); i++ {
if i == 0 {
if (p[i] >= 'a' && p[i] <= 'z') {
p[i] = p[i] - 32
}
} else {
if (p[i] >= 'A' && p[i] <= 'Z') {
p[i] = p[i] + 32
}
}
}
return count, io.EOF
}
Our titlizeReader type will capitalize the first word in the sentence and change all the subsequent letters to lowercase. As we iterate through each byte, we check its ASCII value. The ASCII value of A is 97. The decimal value of a is 65. So, 97 minus 65 equals 32.
Here we use the string's NewReader method to create an io.Reader interface from the string, which is "this IS a tEsT":
func main() {
var r io.Reader
r = strings.NewReader("this IS a tEsT")
r = io.LimitReader(r, 12)
r = NewTitlizeReader(r)
We inpidually assigned the reader value on each line. We could have performed this in one line:
r := NewTitlizeReader(io.LimitReader(strings.NewReader("this IS a tEsT", 12))
We use three Readers: one from the strings package, another free one used to truncate our string to 12 characters, and the one we wrote ourselves.
Given that we have separated our logic into inpidual function calls, Go's concurrency constructs enable us to process them independently to improve performance:
var w io.Writer
w = os.Stdout
io.Copy(w, r)
}
We use the os.Stdout writer to output our results to standard output (our terminal console).
Since we are using the Reader and Writer interfaces, we get to use the io.Copy interface for free.
With Readers and Writers interfaces, we are able to process streams piece by piece. Granted, our example only used a 14-character string, but we could have handled more data than could fit in RAM at the same time.
Gang of Four (GOF) refers to four authors who wrote the Design Patterns: Elements of Reusable Object-Oriented Software (https://en.wikipedia.org/wiki/Design_Patterns) book. Though the examples in the book are in SmallTalk and C++, the book is frequently referenced by many resourceful developers as they build object-oriented software. Languages such as Java, which supports inheritance, can greatly benefit from all the patterns in the GOF book. Not all patterns are equally important for Go. Though, as we saw in the previous chapter, we can definitely benefit from the structural Decorator pattern and the behavioral Strategy pattern.