恭喜你学习围棋!虽然问题是关于示例中的特定错误,但让我们逐行分解并了解一些可能遇到的其他问题:
fname := "D:\myfolder\file.txt"
与 C 和许多其他语言一样,Go 使用反斜杠字符作为“转义序列”。也就是说,某些以反斜杠开头的字符会被翻译成其他难以看到的其他字符(例如,\t 变成制表符,否则可能无法与空格区分开来)。
解决方法是使用未处理转义序列的原始字符串文字(使用反引号而不是引号):
fname := `D:\myfolder\file.txt`
这通过删除无效的\m 和\f 转义序列来修复您看到的初始错误。阅读 Go 规范的 String Literals 部分可以找到完整的转义序列列表和更多解释。
f, err := os.Open(fname)
if err != nil {
fmt.Println(err)
}
这个chunk的第一行很好,但可以改进。如果发生错误,我们的程序没有理由继续执行,因为我们甚至无法打开文件,所以我们应该打印它(可能是标准错误)并退出,最好使用非零退出状态来指示发生了不好的事情。另外,作为一个好习惯,如果打开文件成功,我们可能希望在函数结束时关闭文件。将它放在 Open 调用的正下方是常规的,并且在其他人阅读您的代码时更容易。我将其重写为:
f, err := os.Open(fname)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
// It is also common to replace these two lines with a call to log.Fatal
}
defer f.Close()
最后一个块有点复杂,我们可以用多种方式重写它。现在它看起来像这样:
var buff []byte
defer f.Close()
buff = make([]byte, 1024)
for {
n, err := f.Read(buff)
if n > 0 {
fmt.Println(string(buff[:n]))
}
if err == io.EOF {
break
}
}
但是我们不需要定义我们自己的缓冲,因为标准库为我们提供了bufio 和bytes 包,它们可以为我们做到这一点。不过,在这种情况下,我们可能不需要它们,因为我们也可以通过调用 io.Copy 来替换迭代,它自己进行内部缓冲。如果我们想使用自己的缓冲区,我们也可以使用其他副本变体之一,例如 io.CopyBuffer。它还缺少一些错误处理,所以我们将添加它。现在整个块变成:
_, err := io.Copy(os.Stdout, f)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading from file: `%s'\n", err)
os.Exit(2)
}
// We're done!