我正在观看 FOSDEM '17 上关于在 Go 中实现“tail -f”的演讲 => https://youtu.be/lLDWF59aZAo
在作者最初的示例程序中,他Reader使用文件句柄创建了一个文件,然后使用ReadString带有分隔符“\n”的方法逐行读取文件并打印其内容。我通常使用Scanner,所以这对我来说是新的。
程序如下 | 去游乐场链接
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
fileHandle, err := os.Open("someFile.log")
if err != nil {
log.Fatalln(err)
return
}
defer fileHandle.Close()
reader := bufio.NewReader(fileHandle)
for {
line, err := reader.ReadString('\n')
if err != nil {
log.Fatalln(err)
break
}
fmt.Print(line)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,ReadString采用一个字节作为其分隔符参数[ https://golang.org/pkg/bufio/#Reader.ReadString]
所以我的问题是,到底是如何将 '\n'(即 a )rune转换为 a 的byte?我无法理解这个问题。特别是因为byte是 的别名uint8,并且rune是 的别名int32。
我在 Gophers slack 中问了同样的问题,并被告知 '\n' 不是 a rune,而是一个无类型常量。如果我们实际上创建了一个runeusing '\n' 并将其传入,编译将会失败。这实际上让我更加困惑。
我还获得了 Go 规范中有关 Type Identity => https://golang.org/ref/spec#Type_identity的部分的链接
如果程序不应该编译(如果它是实际的)rune,那么为什么编译器允许通过非类型常量?这不是不安全行为吗?
我的猜测是,这是由于Go 规范中的可分配性部分中的一条规则而起作用的,该规则表示
x 是一个无类型常量,可由类型 T 的值表示。
由于 '\n' 确实可以分配给类型为 的变量byte,因此它被转换。
我的推理正确吗?
TL;DR是的,您是对的,但还有更多内容。
\n\n\'\\n\'是一个无类型符文常量。它没有类型,但有一个默认类型int32(是rune的别名int32)。它保存一个表示文字“\\n”的单个字节,它是数值10:
package main\n\nimport (\n "fmt"\n)\n\nfunc main() {\n fmt.Printf("%T %v %c\\n", \'\\n\', \'\\n\', \'\\n\') // int32 10 (newline)\n}\nRun Code Online (Sandbox Code Playgroud)\n\nhttps://play.golang.org/p/lMjrTFDZUM
\n\n回答您问题的规范部分位于\xc2\xa7 Calls(强调我的):
\n\n\n\n\n给定函数类型 F 的表达式 f,
\n\nRun Code Online (Sandbox Code Playgroud)\n\nf(a1, a2, \xe2\x80\xa6 an)\n使用参数 a1、a2、\xe2\x80\xa6 an 调用 f。除一种特殊情况外,参数必须是可分配给 F 的参数类型的单值表达式,并在调用函数之前进行计算。
\n
“可分配”是这里的关键术语,您引用的规范部分解释了它的含义。正如您所猜对的那样,在各种可分配性规则中,适用于此处的规则如下:
\n\n\n\n\nx 是一个无类型常量,可由类型 T 的值表示。
\n
在我们的例子中,这转化为:
\n\n\n\n\n\'\\n\' 是一个无类型(符文)常量,可由类型值表示
\nbyte
如果我们尝试将宽度大于 1 字节的无类型符文常量\'\\n\'传递ReadString()给需要byte会更加明显:
package main\n\nfunc main() {\n foo(\'\xce\xb1\')\n}\n\nfunc foo(b byte) {}\nRun Code Online (Sandbox Code Playgroud)\n\nhttps://play.golang.org/p/W0EUZppWHH
\n\n上面的代码失败并显示:
\n\n\n\n\ntmp/sandbox120896917/main.go:9:常量 945 溢出字节
\n
那是因为\'\xce\xb1\'实际上是 2 个字节,这意味着它不能转换为 type 的值byte(a 可以容纳的最大整数byte是 255,而\'\xce\xb1\'是 255,而实际上是 945)。
所有这些都在官方博客文章Constants中进行了解释中进行了解释。
\n