课程理解&疑问

来源:7-2 函数式编程例一

merlin丶kael

2022-04-13

以下是我对这节课的理解

  • intGen实现了Read接口, 所以可以当参数 调printFileContent(reader),
  • 当执行 scanner.Scan() 方法时, 会调用 io.Reader.Read()方法, 也就是
  • intGen自己实现的Read方法, 然后会执行fibonacci() 获取 一个斐波那契数列 元素, 也就是
  • scanner.Scan() 方法的返回值.
  • 进入下一个 循环, 一直调用fibonacci()

我的疑问是:
p []byte 数组可能会太小, 但是 调用fibonacci() 获取 斐波那契数列 元素 的逻辑 应该是正确的, 只是 Read函数输出的 值是错误的,
下面这个代码 没看明白

package main

import (
	"fmt"
	"io"
	"strings"
)

// 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
func Fibonacci() func() int {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return a
	}
}

type intGen2 struct {
	gen           func() int
	currentReader io.Reader
}

func (g *intGen2) Read(
	p []byte) (n int, err error) {
	err = io.EOF
	if g.currentReader != nil {
		n, err = g.currentReader.Read(p)
	}
	if err == io.EOF {
		next := g.gen()
		s := fmt.Sprintf("%d\n", next)
		g.currentReader = strings.NewReader(s)
		if n == 0 {
			n, err = g.currentReader.Read(p)
		}
	}
	return n, err
}

func main() {
	f := &intGen2{
		gen: Fibonacci(),
	}
	for i := 0; i < 20; i++ {
		b := make([]byte, 1)
		n, err := f.Read(b)
		fmt.Printf("%d bytes read: %q. err = %v\n", n, b, err)
	}
}
写回答

1回答

ccmouse

2022-05-09

这个代码是我修正所谓p []byte太小的问题。加了一个currentReader来记录当前用来读取数据的Reader。

next := g.gen() s := fmt.Sprintf("%d\n", next) g.currentReader = strings.NewReader(s)

这几行就是把数据读取到一个字符串s,再通过字符串s构造一个Reader,可以用于通过Reader接口读取这个s。

那么我们的问题就变成何时通过上面几行来生成下一个currentReader。答案就是上一个currentReader读取完毕。

所以我们有if err == io.EOF,来指明上一个currentReader读取完毕。

然后还有一个细节,我们只要有currentReader,就从currentReader读取。只要读取的结果(或者没有读取过)是EOF,我们就生成下一个currentReader。但是有一种可能是从currentReader里什么都没读到,直接报了EOF,那么我们也应该从下一个生成的currentReader里来读取,保证我们的Read方法总能读到东西。这就是后面又有一个判断说if n == 0

1
1
merlin丶kael
感谢老师回答
2022-05-10
共1条回复

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程