Go 之旅练习#22:读者,这个问题是什么意思?

问题描述 投票:0回答:7

练习:读者

实现一个 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..
}
go
7个回答
66
投票

啊我明白了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{})
}

4
投票

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
确实是恰到好处。它编写了所需的最少内容,并优雅地使用了内置函数和语法工具,并且永远不会返回错误。


2
投票

最简单的一个:

func (s MyReader) Read(b []byte) (int, error) {
    b[0] = byte('A')
    return 1, nil
}

2
投票

您可以概括这个想法来创建一个永恒的读取器,

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()
实现用字节值填充整个字节切片,而后者写入单个字节。


0
投票

即使没有拼写错误,所谓的答案对我来说也不起作用。 像我一样尝试,该字符串不会进入 b。

func (r MyReader) Read(b []byte) (int,  error) {
    return copy(b, "A"), nil
}

0
投票

我的解决方案:一次添加一个字节,使用闭包存储索引

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{})
}


0
投票

根据给定的切片长度 (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{})
}
© www.soinside.com 2019 - 2024. All rights reserved.