实现 io.Reader 时无限循环中 break 与 return 的不同行为
Different behaviour of break vs. return in infinite loop when implementing io.Reader
我正在进行官方巡演。今天,我在做rot13reader exercise时遇到了一些奇怪的事情。
问题是当我使用 break
而不是 return ttl, io.EOF
时,程序进入了无限循环。然而,据我所知,在这个程序中,break
或 return 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)
}
观察到的行为是由于变量阴影造成的:
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, err
与 return ttl, nil
相同,而与 return ttl, io.EOF
完全不同的原因。
我正在进行官方巡演。今天,我在做rot13reader exercise时遇到了一些奇怪的事情。
问题是当我使用 break
而不是 return ttl, io.EOF
时,程序进入了无限循环。然而,据我所知,在这个程序中,break
或 return 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)
}
观察到的行为是由于变量阴影造成的:
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, err
与 return ttl, nil
相同,而与 return ttl, io.EOF
完全不同的原因。