РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
658 of 1593 menu

Интерфейс fmt.ScanState

Интерфейс fmt.ScanState представляет собой состояние сканера, которое передается в пользовательские методы сканирования. Он позволяет получить доступ к токенам, прочитанным из входного потока, и управлять процессом сканирования.

Данный интерфейс реализуется внутренними структурами пакета fmt и используется в функциях семейства Scan и Fscan. Основное назначение интерфейса - предоставить разработчикам возможность создавать собственные типы, которые могут быть считаны из входного потока.

Методы интерфейса

Интерфейс fmt.ScanState содержит следующие методы:

type ScanState interface { ReadRune() (r rune, size int, err error) UnreadRune() error SkipSpace() error Token(skipSpace bool, f func(rune) bool) (token []byte, err error) Width() (wid int, ok bool) Read(buf []byte) (n int, err error) }

Метод ReadRune читает один рунический символ из потока. Метод UnreadRune отменяет чтение последнего рунического символа.

Метод SkipSpace пропускает все пробельные символы в потоке. Метод Token читает токен из потока, используя функцию для определения границ токена.

Метод Width возвращает ширину, указанную в формате сканирования. Метод Read читает байты в переданный срез.

Пример создания пользовательского типа для сканирования

Создадим пользовательский тип, который реализует интерфейс Scanner и использует fmt.ScanState для чтения данных:

package main import ( "fmt" "strings" ) type Point struct { X, Y int } func (p *Point) Scan(state fmt.ScanState, verb rune) error { state.SkipSpace() state.ReadRune() // skip '(' fmt.Fscanf(state, "%d", &p.X) state.ReadRune() // skip ',' fmt.Fscanf(state, "%d", &p.Y) state.ReadRune() // skip ')' return nil } func main() { var p Point input := "(10,20)" fmt.Sscan(input, &p) fmt.Printf("%+v", p) }

Результат выполнения кода:

{X:10 Y:20}

В данном примере мы создали структуру Point, которая реализует метод Scan. Внутри метода мы используем state.SkipSpace для пропуска пробелов и state.ReadRune для чтения символов.

Пример использования метода Token

Метод Token позволяет читать токены, определяя их границы с помощью пользовательской функции:

package main import ( "fmt" "strings" ) type Word struct { Value string } func (w *Word) Scan(state fmt.ScanState, verb rune) error { token, err := state.Token(false, func(r rune) bool { return r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' }) if err != nil { return err } w.Value = string(token) return nil } func main() { var w Word input := "Hello123World" fmt.Sscan(input, &w) fmt.Printf("%+v", w) }

Результат выполнения кода:

{Value:Hello}

В этом примере метод Token читает только буквенные символы, останавливаясь на цифрах. В результате мы получаем первое слово "Hello".

Пример использования ширины

Метод Width позволяет узнать, задана ли ширина в формате и использовать ее для ограничения чтения:

package main import ( "fmt" "strings" ) type FixedString struct { Value string } func (fs *FixedString) Scan(state fmt.ScanState, verb rune) error { width, ok := state.Width() if !ok { return fmt.Errorf("width not specified") } buf := make([]byte, width) n, err := state.Read(buf) if err != nil { return err } fs.Value = string(buf[:n]) return nil } func main() { var fs FixedString input := "abcdefghij" fmt.Sscanf(input, "%5s", &fs) fmt.Printf("%+v", fs) }

Результат выполнения кода:

{Value:abcde}

В этом примере мы используем ширину для чтения ровно 5 символов. Формат %5s указывает, что нужно прочитать 5 байт.

Пример обработки ошибок

Рассмотрим пример с обработкой ошибок при сканировании:

package main import ( "fmt" "strings" ) type IntPair struct { First, Second int } func (ip *IntPair) Scan(state fmt.ScanState, verb rune) error { state.SkipSpace() _, err := state.ReadRune() if err != nil { return fmt.Errorf("expected '(' but got EOF") } _, err = fmt.Fscan(state, &ip.First) if err != nil { return fmt.Errorf("invalid first number: %v", err) } _, err = state.ReadRune() if err != nil { return fmt.Errorf("expected ',' but got EOF") } _, err = fmt.Fscan(state, &ip.Second) if err != nil { return fmt.Errorf("invalid second number: %v", err) } _, err = state.ReadRune() if err != nil { return fmt.Errorf("expected ')' but got EOF") } return nil } func main() { var ip IntPair input := "(5,10)" _, err := fmt.Sscan(input, &ip) if err != nil { fmt.Printf("Error: %v", err) return } fmt.Printf("%+v", ip) }

Результат выполнения кода:

{First:5 Second:10}

Данный пример демонстрирует правильную обработку ошибок при чтении различных частей входных данных.

Смотрите также

  • интерфейс fmt.Scanner,
    который реализуется для создания пользовательских типов
  • интерфейс fmt.State,
    который используется при форматировании
  • функцию fmt.Sscan,
    которая сканирует строку
  • функцию fmt.Sscanf,
    которая сканирует строку с форматом
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить