Go语言 围棋教程练习#22:读者朋友,这个问题是什么意思?

iswrvxsc  于 2023-01-10  发布在  Go
关注(0)|答案(6)|浏览(151)

Exercise: Readers
实现发出ASCII字符“A”的无限流的Reader类型。
我不明白这个问题,如何发出字符'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..
}
eiee3dmh

eiee3dmh1#

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

68de4m5k2#

io.Reader.Read的作用是将从源读取的数据写入给定的存储器位置。
要实现'A'的流,函数必须使用'A'值写入给定的内存位置。
它不需要填充input中提供的整个切片,它可以决定写入输入切片的多少字节(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; Which makes this non-solution https://play.golang.org/p/aiUyc4UDYi2会因超时而失败。
考虑到这一点,这里提供的解决方案https://stackoverflow.com/a/68077578/4466350return copy(b, "A"), nil非常合适,它编写了所需的最小值,巧妙地使用了内置函数和语法工具,而且从不返回错误。

bybem2ql

bybem2ql3#

所谓的答案是对我不起作用,即使没有错别字,我也试过,那个字符串不会进入B。

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

x7rlezfr4#

我的解决方案:每次只添加一个字节,使用闭包存储索引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{})
}
o3imoua4

o3imoua45#

最简单的一个:

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

91zkwejq6#

你可以把这个想法推广到创建一个永恒的读取器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()实现用字节值填充整个字节片,而后一个实现只写入单个字节。

相关问题