如何按顺序将字符串输入提供给 bufio.Scanner 和 fmt.Scanln?
How do you feed string input to bufio.Scanner and fmt.Scanln sequentially?
这是一个使用 bufio.Scanner 和 fmt.Scanln 的简单程序,它按预期工作:
scanner := bufio.NewScanner(os.Stdin)
var s string
fmt.Println("Enter a string:")
scanner.Scan()
s = scanner.Text()
fmt.Printf("You entered: %q\n\n", s)
var i int
fmt.Println("Enter an int:")
fmt.Scanln(&i)
fmt.Printf("You entered: %d\n", i)
这是程序输出(括号中的文本 [] 是键盘输入)
Enter a string:
[mary had a little lamb]
You entered: "mary had a little lamb"
Enter an int:
[42]
You entered: 42
现在,我们不使用默认的标准输入,而是使用管道从字符串而不是键盘重定向输入。
readStdin, writeStdin, err := os.Pipe()
if err != nil {
fmt.Println("Pipe Error:", err)
return
}
os.Stdin = readStdin
writeStdin.WriteString("mary had a little lamb\n42\n")
scanner := bufio.NewScanner(os.Stdin)
var s string
fmt.Println("Enter a string:")
scanner.Scan()
s = scanner.Text()
fmt.Printf("You entered: %q\n\n", s)
var i int
fmt.Println("Enter an int:")
fmt.Scanln(&i)
fmt.Printf("You entered: %d\n", i)
readStdin.Close()
程序输出如下:
Enter a string:
You entered: "mary had a little lamb"
Enter an int:
在“输入一个整数:”提示后,程序无限期等待,必须手动终止。 :(
奇怪的是,如果我颠倒事件的顺序(fmt.Scanln 在 bufio.Scanner.Scan 之前),那么它会完美运行。如果我专门使用 fmt.Scanln 或专门使用 bufio.Scanner.Scan.
它也可以正常工作
所有这些让我觉得:
a) Go 处理键盘输入的方式有一些独特之处
b) 在使用 bufio.Scanner.Scan
扫描时,我应该使用其他类型的分隔符
c) 永远不要同时使用这两种扫描机制(请不要让它成为答案!)
bufio.Scanner
使用缓冲区读取输入的一大块,然后 returns 该缓冲区的各个部分。当您使用管道写入完整的输入时,bufio.Scanner
只是读取整个输入,returns 两个由换行符分隔的标记。 fmt.Scanln
将始终从标准输入读取。在 fmt.Scanln
运行时,bufio.Scanner
已经读取了完整的输入,所以 fmt.Scanln
只是等待。如果您在开始时睡眠,并在程序开始读取之前键入所有输入,那么第一个程序也会发生同样的事情。所以这与 Go 如何处理输入或扫描分隔符无关。
如果您使用缓冲 i/o,您必须预料到缓冲区中的内容会超出您的需要。所以,不要将两者混用,或者在你用完扫描仪后使用fmt.Scanln
。
这是一个使用 bufio.Scanner 和 fmt.Scanln 的简单程序,它按预期工作:
scanner := bufio.NewScanner(os.Stdin)
var s string
fmt.Println("Enter a string:")
scanner.Scan()
s = scanner.Text()
fmt.Printf("You entered: %q\n\n", s)
var i int
fmt.Println("Enter an int:")
fmt.Scanln(&i)
fmt.Printf("You entered: %d\n", i)
这是程序输出(括号中的文本 [] 是键盘输入)
Enter a string:
[mary had a little lamb]
You entered: "mary had a little lamb"
Enter an int:
[42]
You entered: 42
现在,我们不使用默认的标准输入,而是使用管道从字符串而不是键盘重定向输入。
readStdin, writeStdin, err := os.Pipe()
if err != nil {
fmt.Println("Pipe Error:", err)
return
}
os.Stdin = readStdin
writeStdin.WriteString("mary had a little lamb\n42\n")
scanner := bufio.NewScanner(os.Stdin)
var s string
fmt.Println("Enter a string:")
scanner.Scan()
s = scanner.Text()
fmt.Printf("You entered: %q\n\n", s)
var i int
fmt.Println("Enter an int:")
fmt.Scanln(&i)
fmt.Printf("You entered: %d\n", i)
readStdin.Close()
程序输出如下:
Enter a string:
You entered: "mary had a little lamb"
Enter an int:
在“输入一个整数:”提示后,程序无限期等待,必须手动终止。 :(
奇怪的是,如果我颠倒事件的顺序(fmt.Scanln 在 bufio.Scanner.Scan 之前),那么它会完美运行。如果我专门使用 fmt.Scanln 或专门使用 bufio.Scanner.Scan.
它也可以正常工作所有这些让我觉得:
a) Go 处理键盘输入的方式有一些独特之处
b) 在使用 bufio.Scanner.Scan
扫描时,我应该使用其他类型的分隔符
c) 永远不要同时使用这两种扫描机制(请不要让它成为答案!)
bufio.Scanner
使用缓冲区读取输入的一大块,然后 returns 该缓冲区的各个部分。当您使用管道写入完整的输入时,bufio.Scanner
只是读取整个输入,returns 两个由换行符分隔的标记。 fmt.Scanln
将始终从标准输入读取。在 fmt.Scanln
运行时,bufio.Scanner
已经读取了完整的输入,所以 fmt.Scanln
只是等待。如果您在开始时睡眠,并在程序开始读取之前键入所有输入,那么第一个程序也会发生同样的事情。所以这与 Go 如何处理输入或扫描分隔符无关。
如果您使用缓冲 i/o,您必须预料到缓冲区中的内容会超出您的需要。所以,不要将两者混用,或者在你用完扫描仪后使用fmt.Scanln
。