Почему используется новая строка после %d, но не %c в fmt.Scanf?

# #go

Вопрос:

 package main

import (
    "fmt"
    "log"
)

func main() {
    var num int
    n, err := fmt.Scanf("%d", amp;num)
    fmt.Println(n, num)
    if err != nil {
        log.Fatalln(err)
    }

    var r1 rune
    n, err = fmt.Scanf("%c", amp;r1)
    fmt.Println(n, r1)
    if err != nil {
        log.Fatalln(err)
    }

    var r2 rune
    n, err = fmt.Scanf("%c", amp;r2)
    fmt.Println(n, r2)
    if err != nil {
        log.Fatalln(err)
    }
}
 

ввод (клавиши клавиатуры):
1 enter a enter

вывод:
1 1
1 97
1 10

Почему значение r2 n равно, но значение r1 равно a ?

В комментарии к fmt.Scanf :

Новые строки во входных данных должны соответствовать новым строкам в формате. Единственное исключение: глагол %c всегда сканирует следующую руну во входных данных, даже если это пробел (или табуляция и т. Д.) Или новая строка.

Кажется, что новая строка после %d съедается, а новая строка после %c — нет. Соответствует ли новая строка после %d пропуска?

Другой пример: https://play.studygolang.com/p/lRgxrUqyBTI , я пытаюсь использовать буфер для замены stdin, но результат отличается от использования stdin.

версия go go version go1.17.1 windows/amd64

Комментарии:

1. Однако вы не соответствуете новым строкам в формате, хотя вы процитировали документ, где вы сказали, что должны были.

2. n, err = fmt.Scanf("%c", amp;r1) . Я не знаю, почему %c не соответствует новой строке после %d , другими словами, первая enter съедается.

3. ааа, понял. Спасибо. Ввод с терминала затрудняет воспроизведение подобных вопросов. Я не смог получить поведение, которое вы описываете для буферизованного ввода: play.golang.org/p/usHn6UhiKTU — Я понимаю 1 1 1 10 1 97 , чего мы и ожидали. Думаете, вы можете воспроизвести свою проблему на такой игровой площадке?

4. Спасибо за ваш ответ. Результат получается 1 1 1 97 1 10 , когда я запускаю код в IDE GoLand и набираю 1 enter a enter напрямую, но результат 1 1 1 10 1 97 (такой же, как у вас), когда я запускаю код с go run main.go помощью command и набираю 1 enter a enter текст.

5. Я очень внимательно просмотрел документацию, и, честно говоря, я даже не вижу, где задокументировано, что новая строка заканчивается Scanf. Поэтому я думаю, что это хороший вопрос, поскольку рассматриваемая функция, по-видимому, недостаточно документирована. Если вы не получите хорошего ответа, напомните мне, и я щедро вознагражду это

Ответ №1:

новая строка — это один символ, который является допустимым вводом для руны, но не для int, поэтому при захвате руны новая строка считывается и сохраняется, в то время как для других типов это не делается.

если вы не захватите новую строку во время чтения в руну, вы получите сообщение об ошибке «неожиданное новое значение», если вы снова попытаетесь прочитать из стандартного ввода.

я предлагаю вам сделать следующее для чтения рун, чтобы вы всегда фиксировали новую строку и не получали неожиданных результатов

 var r1, r2 rune
n, err = fmt.Scanf("%c%c", amp;r1, amp;r2)
fmt.Println(n, r1, r2)
if err != nil {
    log.Fatalln(err)
}