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

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

Метод Format принимает два параметра: первый параметр state - это интерфейс fmt.State, предоставляющий доступ к информации о флагах форматирования и ширине поля; второй параметр verb - это символ (например, 'v', 's', 'd'), указывающий, с каким флагом форматирования было вызвано значение.

Реализуя этот интерфейс, вы можете полностью контролировать текстовое представление ваших типов в зависимости от используемого флага и дополнительных параметров форматирования.

Синтаксис

gotype Formatter interface {
  Format(state fmt.State, verb rune)
}

Пример

Давайте создадим тип Person и реализуем для него интерфейс fmt.Formatter, чтобы при выводе с флагом 'v' отображалось полное имя, а с флагом 's' - только имя:

gopackage main

import (
  "fmt"
  "io"
)

type Person struct {
  Name  string
  Surname string
}

func (p Person) Format(state fmt.State, verb rune) {
  switch verb {
  case 'v':
    io.WriteString(state, p.Name+" "+p.Surname)
  case 's':
    io.WriteString(state, p.Name)
  default:
    io.WriteString(state, fmt.Sprint(p))
  }
}

func main() {
  p := Person{Name: "John", Surname: "Doe"}
  fmt.Printf("%v\n", p)
  fmt.Printf("%s\n", p)
}

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

go"John Doe"
"John"

Пример

Теперь рассмотрим пример, где форматирование зависит от дополнительных флагов, таких как ширина поля. Создадим тип Number, который при выводе с флагом 'd' будет отображать число с ведущими нулями, если указана ширина:

gopackage main

import (
  "fmt"
  "io"
)

type Number int

func (n Number) Format(state fmt.State, verb rune) {
  if verb == 'd' {
    width, hasWidth := state.Width()
    if hasWidth && width > 0 {
      io.WriteString(state, fmt.Sprintf("%0*d", width, n))
      return
    }
    io.WriteString(state, fmt.Sprintf("%d", n))
    return
  }
  io.WriteString(state, fmt.Sprint(n))
}

func main() {
  num := Number(42)
  fmt.Printf("%d\n", num)
  fmt.Printf("%5d\n", num)
}

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

go"42"
"00042"

Пример

В этом примере мы реализуем интерфейс fmt.Formatter для типа Color, чтобы при выводе с флагом 'v' отображалось название цвета в цветных скобках, а с флагом 's' - только название цвета в верхнем регистре:

gopackage main

import (
  "fmt"
  "io"
  "strings"
)

type Color string

func (c Color) Format(state fmt.State, verb rune) {
  switch verb {
  case 'v':
    io.WriteString(state, "["+string(c)+"]")
  case 's':
    io.WriteString(state, strings.ToUpper(string(c)))
  default:
    io.WriteString(state, fmt.Sprint(c))
  }
}

func main() {
  color := Color("red")
  fmt.Printf("%v\n", color)
  fmt.Printf("%s\n", color)
}

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

go"[red]"
"RED"

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

  • интерфейс fmt.Stringer,
    который определяет метод String для строкового представления типа
  • интерфейс fmt.GoStringer,
    который определяет метод GoString для представления типа в формате Go
  • интерфейс fmt.State,
    который предоставляет информацию о параметрах форматирования
  • функцию fmt.Printf,
    которая использует Formatter для вывода значений