Skip to content

proposal: io: add ReaderFunc and WriterFunc #47678

@dsnet

Description

@dsnet

I propose adding the following:

type ReaderFunc func([]byte) (int, error)
func (f ReaderFunc) Read(b []byte) (int, error) {
    return f(b)
}

type WriterFunc func([]byte) (int, error)
func (f WriterFunc ) Write(b []byte) (int, error) {
    return f(b)
}

In tests, I find it common that I need an io.Reader or io.Writer with specialized behavior. Usually, this is only necessary for a single test case within a large table-driven test. In order to have a customized io.Reader, I need to declare a concrete type to implement the Read method. Since you can only declare a type with methods at the top-level, this results in the declaration potentially being located far away from the code actually using it.

The proposed ReaderFunc (and WriterFunc) allows me to create an io.Reader that 1) requires no named declarations, and 2) have the specialized Read behavior inlined with the place that actually plans on using it.

Example usage:

// Cancel the request after the first read to abruptly end the stream.
var calls int
ctx, cancel := context.WithCancel(context.Background())
req, err := http.NewRequest("POST", url, io.ReaderFunc(func(b []byte) (int, error) {
	if calls > 0 {
		cancel()
	}
	calls++
	return copy(b, []byte("whatever")), nil
}))
req = req.WithContext(ctx)

This a library-specific workaround to the several proposed language changes (see #21670, #25860, #47487, and many others). Being a non-language change, it is presumably a more palatable change than a full language change. I personally can only recall ever needing something like #21670 for io.Reader and io.Writer.

This is very similar to the existing http.HandlerFunc type.

\cc @josharian

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Hold

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions