实现一个 Reader 类型,发出 ASCII 字符“A”的无限流。
我不明白这个问题,如何发出字符“A”?我应该将该字符设置到哪个变量中?
这是我尝试过的:
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
// TODO: Add a Read([]byte) (int, error) method to MyReader.
func main() {
reader.Validate(MyReader{}) // what did this function expect?
}
func (m MyReader) Read(b []byte) (i int, e error) {
b = append(b, 'A') // this is wrong..
return 1, nil // this is also wrong..
}
啊我明白了XD
我认为更好的说法是:“将
[]byte
中的所有值重写为'A'
s”
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
// TODO: Add a Read([]byte) (int, error) method to MyReader.
func (m MyReader) Read(b []byte) (i int, e error) {
for x := range b {
b[x] = 'A'
}
return len(b), nil
}
func main() {
reader.Validate(MyReader{})
}
io.Reader.Read
的作用是用从源读取的数据写入给定的内存位置。
要实现
'A'
流,该函数必须使用 'A'
值写入给定的内存位置。
不需要填写输入中提供的整个切片,它可以决定写入输入切片的多少字节(
Read reads up to len(p) bytes into p
),它必须返回该数字以向消费者指示数据的长度过程。
按照惯例,
io.Reader
通过返回io.EOF
错误来指示其结束。如果阅读器不返回错误,那么它对于消费者来说就像无限的数据源,永远无法检测到退出条件。
请注意,对
Read
的调用可能会返回 0 bytes
read ,但并不表示任何特殊情况, Callers should treat a return of 0 and nil as indicating that nothing happened;
这使得这不是解决方案 https://play.golang.org/p/aiUyc4UDYi2超时失败。
就此而言,这里提供的解决方案https://stackoverflow.com/a/68077578/4466350
return copy(b, "A"), nil
确实是恰到好处。它编写了所需的最少内容,并优雅地使用了内置函数和语法工具,并且永远不会返回错误。
最简单的一个:
func (s MyReader) Read(b []byte) (int, error) {
b[0] = byte('A')
return 1, nil
}
您可以概括这个想法来创建一个永恒的读取器,
alwaysReader
,您总是从中一遍又一遍地读取相同的字节值(它永远不会导致 EOF):
package readers
type alwaysReader struct {
value byte
}
func (r alwaysReader) Read(p []byte) (n int, err error) {
for i := range p {
p[i] = r.value
}
return len(p), nil
}
func NewAlwaysReader(value byte) alwaysReader {
return alwaysReader { value }
}
NewAlwaysReader()
是 alwaysReader
的构造函数(未导出)。 NewAlwaysReader('A')
的结果是您将永远阅读的读者 'A'
。
澄清单元测试
alwaysReader
:
package readers_test
import (
"bytes"
"io"
"readers"
"testing"
)
func TestEmptyReader(t *testing.T) {
const numBytes = 128
const value = 'A'
buf := bytes.NewBuffer(make([]byte, 0, numBytes))
reader := io.LimitReader(readers.NewAlwaysReader(value), numBytes)
n, err := io.Copy(buf, reader)
if err != nil {
t.Fatal("copy failed: %w")
}
if n != numBytes {
t.Errorf("%d bytes read but %d expected", n, numBytes)
}
for i, elem := range buf.Bytes() {
if elem != value {
t.Errorf("byte at position %d has not the value %v but %v", i, value, elem)
}
}
}
因为我们可以永远从
alwaysReader
中读取,所以我们需要用 io.LimitReader
来装饰它,这样我们最终最多可以从中读取 numBytes
。否则,由于 bytes.Buffer
,
io.Copy()
最终将耗尽内存来重新分配其内部缓冲区。
请注意,以下
Read()
对于 alwaysReader
的实现也是有效的:
func (r alwaysReader) Read(p []byte) (n int, err error) {
if len(p) > 0 {
p[0] = r.value
return 1, nil
}
return 0, nil
}
前一个
Read()
实现用字节值填充整个字节切片,而后者写入单个字节。
即使没有拼写错误,所谓的答案对我来说也不起作用。 像我一样尝试,该字符串不会进入 b。
func (r MyReader) Read(b []byte) (int, error) {
return copy(b, "A"), nil
}
我的解决方案:一次添加一个字节,使用闭包存储索引
i
。
package main
import (
"golang.org/x/tour/reader"
)
type MyReader struct{}
func (mr MyReader) Read(b []byte) (int, error) {
i := 0
p := func () int {
b[i] = 'A'
i += 1
return i
}
return p(), nil
}
func main() {
reader.Validate(MyReader{})
}
根据给定的切片长度 (1..n),练习可以实现为:
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
const slice_length = 8 // the number of populated bytes of data (1..n)
func (MyReader) Read(b []byte) (int, error) {
for i := 0; i < slice_length; i++ {
b[i] = 'A'
}
return slice_length, nil
}
func main() {
reader.Validate(MyReader{})
}