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

Интерфейс fmt.State предоставляет доступ к состоянию форматтера во время выполнения пользовательских операций форматирования. Он используется в методах типа Formatter, передаваясь как первый аргумент в метод Format. Интерфейс позволяет получить информацию о ширине и точности вывода, а также о текущем флаге форматирования.

Синтаксис

gotype State interface {
  Write(b []byte) (n int, err error)
  Width() (wid int, ok bool)
  Precision() (prec int, ok bool)
  Flag(c int) bool
}

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

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

Пример

Давайте реализуем пользовательский тип с поддержкой форматирования через интерфейс fmt.Formatter, который использует fmt.State:

gopackage main

import (
  "fmt"
)

type Person struct {
  Name string
  Age  int
}

func (p Person) Format(state fmt.State, verb rune) {
  switch verb {
  case 's':
    state.Write([]byte(p.Name))
  case 'd':
    fmt.Fprintf(state, "%d", p.Age)
  case 'v':
    if state.Flag('+') {
      fmt.Fprintf(state, "Name: %s, Age: %d", p.Name, p.Age)
    } else {
      fmt.Fprintf(state, "%s (%d)", p.Name, p.Age)
    }
  default:
    fmt.Fprintf(state, "%%!%c(Person=%s)", verb, p.Name)
  }
}

func main() {
  p := Person{Name: "Alice", Age: 30}
  fmt.Println(p)
  fmt.Printf("%+v\n", p)
  fmt.Printf("%s\n", p)
  fmt.Printf("%d\n", p)
}

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

go"Alice (30)"
"Name: Alice, Age: 30"
"Alice"
"30"

Пример

Рассмотрим пример использования методов Width и Precision для управления выводом:

gopackage main

import (
  "fmt"
)

type Number struct {
  Value float64
}

func (n Number) Format(state fmt.State, verb rune) {
  width, hasWidth := state.Width()
  prec, hasPrec := state.Precision()

  if !hasPrec {
    prec = 2
  }

  if hasWidth {
    fmt.Fprintf(state, "%*.*f", width, prec, n.Value)
  } else {
    fmt.Fprintf(state, "%.*f", prec, n.Value)
  }
}

func main() {
  num := Number{Value: 3.14159}
  fmt.Println(num)
  fmt.Printf("%10.3f\n", num)
  fmt.Printf("%.1f\n", num)
}

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

go"3.14"
"   3.142"
"3.1"

Пример

Давайте создадим тип, который обрабатывает различные флаги форматирования:

gopackage main

import (
  "fmt"
)

type Color struct {
  Red   int
  Green int
  Blue  int
}

func (c Color) Format(state fmt.State, verb rune) {
  switch verb {
  case 'v':
    if state.Flag('#') {
      fmt.Fprintf(state, "#%02X%02X%02X", c.Red, c.Green, c.Blue)
    } else if state.Flag('+') {
      fmt.Fprintf(state, "R:%d G:%d B:%d", c.Red, c.Green, c.Blue)
    } else {
      fmt.Fprintf(state, "(%d, %d, %d)", c.Red, c.Green, c.Blue)
    }
  default:
    fmt.Fprintf(state, "%%!%c(Color)", verb)
  }
}

func main() {
  color := Color{Red: 255, Green: 128, Blue: 0}
  fmt.Println(color)
  fmt.Printf("%+v\n", color)
  fmt.Printf("%#v\n", color)
}

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

go"(255, 128, 0)"
"R:255 G:128 B:0"
"#FF8000"

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

  • интерфейс fmt.Formatter,
    который определяет метод для пользовательского форматирования
  • функцию fmt.Printf,
    которая форматирует и выводит данные с использованием спецификаторов
  • функцию fmt.Sprintf,
    которая возвращает отформатированную строку
  • спецификатор %v,
    который используется для стандартного форматирования значений