当作为方法 arg 传递时,无类型常量 '\n' 如何转换为字节?

kka*_*nja 3 go

我正在观看 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,因此它被转换。

我的推理正确吗?

Agi*_*gis 5

TL;DR是的,您是对的,但还有更多内容。

\n\n

\'\\n\'是一个无类型符文常量。它没有类型,但有一个默认类型int32(是rune的别名int32)。它保存一个表示文字“\\n”的单个字节,它是数值10

\n\n
package main\n\nimport (\n    "fmt"\n)\n\nfunc main() {\n    fmt.Printf("%T %v %c\\n", \'\\n\', \'\\n\', \'\\n\') // int32 10 (newline)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

https://play.golang.org/p/lMjrTFDZUM

\n\n

回答您问题的规范部分位于\xc2\xa7 Calls(强调我的):

\n\n
\n

给定函数类型 F 的表达式 f,

\n\n
f(a1, a2, \xe2\x80\xa6 an)\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用参数 a1、a2、\xe2\x80\xa6 an 调用 f。除一种特殊情况外,参数必须是可分配给 F 的参数类型的单值表达式,并在调用函数之前进行计算。

\n
\n\n

“可分配”是这里的关键术语,您引用的规范部分解释了它的含义。正如您所猜对的那样,在各种可分配性规则中,适用于此处的规则如下:

\n\n
\n

x 是一个无类型常量,可由类型 T 的值表示。

\n
\n\n

在我们的例子中,这转化为:

\n\n
\n

\'\\n\' 是一个无类型(符文)常量,可由类型值表示byte

\n
\n\n

如果我们尝试将宽度大于 1 字节的无类型符文常量\'\\n\'传递ReadString()给需要byte会更加明显:

\n\n
package main\n\nfunc main() {\n    foo(\'\xce\xb1\')\n}\n\nfunc foo(b byte) {}\n
Run Code Online (Sandbox Code Playgroud)\n\n

https://play.golang.org/p/W0EUZppWHH

\n\n

上面的代码失败并显示:

\n\n
\n

tmp/sandbox120896917/main.go:9:常量 945 溢出字节

\n
\n\n

那是因为\'\xce\xb1\'实际上是 2 个字节,这意味着它不能转换为 type 的值byte(a 可以容纳的最大整数byte是 255,而\'\xce\xb1\'是 255,而实际上是 945)。

\n\n

所有这些都在官方博客文章Constants中进行了解释中进行了解释。

\n