I feel so stupid. Something like interfaces are so crucial to understand, especially when using a programming language like Golang. In Golang, “interfaces are implemented implicitly”. Today this really clicked for me, and I hope to make it click for you as well.
To give context, I am writing a test to ensure my function handles an io.ReadCloser
input that is not nil
, but will cause json.Decode
to fail.
My first thought was to use bytes.NewBufferString(
“{‘test’: ’bad}”)
, but got the following error when trying to assign to http.Response.Body
.
./utils_test.go:30:14: cannot use bytes.NewBufferString("{\"test\":\"bad}") (type *bytes.Buffer) as type io.ReadCloser in assignment:
*bytes.Buffer does not implement io.ReadCloser (missing Close method)
FAIL github.com/oglinuk/restful-go/cmd/ui [build failed]
The key that I’ve always glossed over in the above output is (missing Close method)
.
If we look at the interface type section of the Golang specification, it states “An interface type specifies a method set called its interface.” If we look at the method sets section, it states “A type has a (possibly empty) method set associated with it. The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T.”
The key sentence is “The method set of any other T consists of all methods declard with receiver type T”. In our context, the receiver type is ReadCloser
, and the method set is “the basic Read and Close methods.” The bytes.Buffer
struct implements the Read
method, but not the Close
method.
When going to io.ReadCloser
, I came across io.NopCloser
, which " returns a ReadCloser with a no-op Close method wrapping the provided Reader r."
I encourage you to write your own test for the following code.
package main
import (
"encoding/json"
"fmt"
"io"
)
func decodeJSON(v interface{}, body io.ReadCloser) error {
if v == nil {
return fmt.Errorf("decodeJSON::v is nil")
}
if body == nil {
return fmt.Errorf("decodeJSON::body is nil")
}
defer body.Close()
:= json.NewDecoder(body).Decode(&v)
err if err != nil {
return err
}
return nil
}
Don’t downplay progress, cause you never know when reality will hit you in the face.
Related:
Tags:
#imposter-syndrome #click-moment #go-interfaces #go-method-sets #go-testing