实现io.Reader时,中断与返回的不同行为会无限循环返回

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

我正在进行正式巡回演出。今天,我在进行rot13reader exercise时遇到了一些奇怪的事情。

问题是当我使用break而不是return ttl, io.EOF时,程序进入了无限循环。但是,据我所知,在此程序中,breakreturn ttl, io.EOF应该没有区别,因为如果是break,则下一行将是return ttl, err方法的末尾是Read() ,与return ttl, io.EOF相同。

我想知道为什么。与Go处理io.Reader接口及其实现的基本机制有什么关系?

这里是代码。

package main

import (
    "io"
    "os"
    "strings"
)

type rot13Reader struct {
    r io.Reader
}

func (rr *rot13Reader) Read(b []byte) (n int, err error) {
    rb := make([]byte, 8)
    var ttl int
    for {
        n, err := rr.r.Read(rb)
        if err == io.EOF {
            return ttl, io.EOF
            // break <----------------------------here's the problem
        } else if err != nil {
            panic(err)
        } else {
            for i, c := range rb[:n] {
                b[i+ttl] = decodeRot13(c)
            }
            ttl += n
        }
    }
    return ttl, err
}

func decodeRot13(c byte) byte {
    if c >= 97 && c <= 122 { // a-z: 97 122
        c += 13
        if c > 122 {
            c -= 26
        }
    } else if c >= 65 && c <= 90 { // A-Z: 65 90
        c += 13
        if c > 90 {
            c -= 26
        }
    }
    return c
}

func main() {
    s := strings.NewReader("Lbh penpxrq gur pbqr!")
    r := rot13Reader{s}
    io.Copy(os.Stdout, &r)
}
go interface infinite-loop break
1个回答
0
投票

观察到的行为是由于可变阴影:

func (rr *rot13Reader) Read(b []byte) (n int, err error) { // <-- this 'err'
    rb := make([]byte, 8)
    var ttl int
    for {
        n, err := rr.r.Read(rb) // <-- and this 'err' are different
        if err == io.EOF {
            return ttl, io.EOF
            // break <----------------------------here's the problem
        } else if err != nil {
            panic(err)
        } else {
            for i, c := range rb[:n] {
                b[i+ttl] = decodeRot13(c)
            }
            ttl += n
        }
    }
    return ttl, err
}

在此行:

        n, err := rr.r.Read(rb) // <-- and this 'err' are different

由于':='赋值,将创建一个新的err实例,该实例遮盖了在较高范围定义的实例。这意味着当您退出for循环时,此版本的err不可用,并且使用了设置为nil的更高范围的版本。

这就是return ttl, errreturn ttl, nil相同,而与return ttl, io.EOF完全不同的原因。

© www.soinside.com 2019 - 2024. All rights reserved.