Как последовательно передавать строковый ввод в bufio.Scanner и fmt.Scanln? - PullRequest
0 голосов
/ 02 августа 2020

Вот простая программа, использующая 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:

После приглашения «Enter an int:» программа ожидает неопределенное время и должна быть вручную остановлена. : (

Странно то, что если я изменю порядок событий (fmt.Scanln перед bufio.Scanner.Scan), то он работает отлично. Он также отлично работает, если я использую исключительно fmt.Scanln или исключительно используйте bufio.Scanner.Scan.

Все это заставляет меня думать:

a) Есть что-то уникальное в том, как Go обрабатывает ввод с клавиатуры
b) Там это какой-то другой тип разделителя, который я должен использовать при сканировании с помощью bufio.Scanner.Scan
c) Просто никогда не используйте эти два механизма сканирования вместе (пожалуйста, не позволяйте этому быть ответом!)

1 Ответ

0 голосов
/ 02 августа 2020

bufio.Scanner использует буфер для чтения фрагмента ввода, а затем возвращает части этого буфера. Когда вы записываете весь ввод с помощью конвейера, bufio.Scanner просто считывает весь ввод и возвращает два токена, разделенных символом новой строки. fmt.Scanln всегда будет читать из стандартного ввода. К моменту запуска fmt.Scanln bufio.Scanner уже прочитает весь ввод, поэтому fmt.Scanln просто ждет. То же самое произойдет с первой программой, если вы поставите вначале засыпание и введете весь ввод до того, как программа начнет чтение. Так что это не имеет ничего общего с тем, как Go обрабатывает ввод или ограничители сканирования.

Если вы используете буферизованный ввод-вывод, вы должны ожидать, что в буфере будет больше материала, чем вам нужно. Поэтому не смешивайте их и не используйте fmt.Scanln после полного использования сканера.

...