Язык Go — пакет fmt (часть 3)
Справочник по функциям пакета fmt — Append, Errorf, Fprint, Fprintf, Fprintln, Fscan, Fscanf, Fscanln, Print, Println, Printf, Sprint, Sprintf, Sprintln, Sscan, Sscanf, Sscanln и интерфейсы Formatter, GoStringer, Scanner, Stringer.
Содержание
Эта статья — справочник по функциям и интерфейсам пакета fmt. Для понимания глаголов форматирования, флагов и правил вывода см. часть 1, для сканирования — часть 2.
Функции
Append, Appendf, Appendln
func Append(b []byte, a ...any) []byte
func Appendf(b []byte, format string, a ...any) []byte
func Appendln(b []byte, a ...any) []byte
Добавляют форматированный результат к срезу байт и возвращают обновлённый срез. Добавлены в Go 1.19.
Append— формат по умолчанию; пробел между операндами добавляется только если ни один из них не является строкойAppendf— форматирование по строке форматаAppendln— формат по умолчанию; пробелы добавляются всегда, в конце добавляется перенос строки
Errorf
func Errorf(format string, a ...any) (err error)
Форматирует строку по строке формата и возвращает её как значение типа error.
Если строка формата содержит глагол %w с операндом типа error, возвращаемая ошибка реализует метод Unwrap, возвращающий этот операнд. Если глаголов %w несколько — Unwrap вернёт []error со всеми такими операндами в порядке их появления в аргументах. Передавать в %w значение, не реализующее интерфейс error, недопустимо. Во всём остальном %w является синонимом %v.
package main
import (
"fmt"
)
func main() {
const name, id = "bueller", 17
err := fmt.Errorf("user %q (id %d) not found", name, id)
fmt.Println(err.Error())
// Выведет: user "bueller" (id 17) not found
}
FormatString
func FormatString(state State, verb rune) string
Возвращает строку, представляющую полную директиву форматирования, захваченную State, с добавлением глагола. (Сам State глагол не содержит.) Результат начинается со знака %, за которым следуют флаги, ширина и точность — отсутствующие элементы опускаются. Функция позволяет типу, реализующему Formatter, восстановить исходную директиву, вызвавшую Format. Добавлена в Go 1.20.
Fprint
func Fprint(w io.Writer, a ...any) (n int, err error)
Форматирует аргументы в формате по умолчанию и пишет в w. Пробел между операндами добавляется только если ни один из них не является строкой. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
"os"
)
func main() {
const name, age = "Kim", 22
n, err := fmt.Fprint(os.Stdout, name, " is ", age, " years old.\n")
// Возвращаемые n и err — это значения, возвращённые
// нижележащим io.Writer.
if err != nil {
fmt.Fprintf(os.Stderr, "Fprint: %v\n", err)
}
fmt.Print(n, " bytes written.\n")
// Выведет: Kim is 22 years old.
// Выведет: 21 bytes written.
}
Fprintf
func Fprintf(w io.Writer, format string, a ...any) (n int, err error)
Форматирует аргументы по строке формата и пишет в w. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
"os"
)
func main() {
const name, age = "Kim", 22
n, err := fmt.Fprintf(os.Stdout, "%s is %d years old.\n", name, age)
// Возвращаемые n и err — это значения, возвращённые
// нижележащим io.Writer.
if err != nil {
fmt.Fprintf(os.Stderr, "Fprintf: %v\n", err)
}
fmt.Printf("%d bytes written.\n", n)
// Выведет: Kim is 22 years old.
// Выведет: 21 bytes written.
}
Fprintln
func Fprintln(w io.Writer, a ...any) (n int, err error)
Форматирует аргументы в формате по умолчанию и пишет в w. Пробелы добавляются всегда, в конце добавляется перенос строки. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
"os"
)
func main() {
const name, age = "Kim", 22
n, err := fmt.Fprintln(os.Stdout, name, "is", age, "years old.")
// Возвращаемые n и err — это значения, возвращённые
// нижележащим io.Writer.
if err != nil {
fmt.Fprintf(os.Stderr, "Fprintln: %v\n", err)
}
fmt.Println(n, "bytes written.")
// Выведет: Kim is 22 years old.
// Выведет: 21 bytes written.
}
Fscan
func Fscan(r io.Reader, a ...any) (n int, err error)
Читает текст из r, сохраняя разделённые пробелами значения в последовательные аргументы. Переносы строк считаются пробелами. Возвращает количество успешно просканированных элементов. Если оно меньше числа аргументов — err сообщит причину.
Fscanf
func Fscanf(r io.Reader, format string, a ...any) (n int, err error)
Читает текст из r, разбирая значения по строке формата. Возвращает количество успешно разобранных элементов. Переносы строк во вводе должны соответствовать переносам строк в формате.
package main
import (
"fmt"
"os"
"strings"
)
func main() {
var (
i int
b bool
s string
)
r := strings.NewReader("5 true gophers")
n, err := fmt.Fscanf(r, "%d %t %s", &i, &b, &s)
if err != nil {
fmt.Fprintf(os.Stderr, "Fscanf: %v\n", err)
}
fmt.Println(i, b, s) // Выведет: 5 true gophers
fmt.Println(n) // Выведет: 3
}
Fscanln
func Fscanln(r io.Reader, a ...any) (n int, err error)
Аналогична Fscan, но останавливается на переносе строки. После последнего элемента должен быть перенос строки или EOF.
package main
import (
"fmt"
"io"
"strings"
)
func main() {
s := `dmr 1771 1.61803398875
ken 271828 3.14159`
r := strings.NewReader(s)
var a string
var b int
var c float64
for {
n, err := fmt.Fscanln(r, &a, &b, &c)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
fmt.Printf("%d: %s, %d, %f\n", n, a, b, c)
}
// Выведет: 3: dmr, 1771, 1.618034
// Выведет: 3: ken, 271828, 3.141590
}
func Print(a ...any) (n int, err error)
Форматирует аргументы в формате по умолчанию и пишет в стандартный вывод. Пробел между операндами добавляется только если ни один из них не является строкой. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
fmt.Print(name, " is ", age, " years old.\n")
// По соглашению ошибку, возвращаемую Print, обычно игнорируют.
// Выведет: Kim is 22 years old.
}
Printf
func Printf(format string, a ...any) (n int, err error)
Форматирует аргументы по строке формата и пишет в стандартный вывод. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
fmt.Printf("%s is %d years old.\n", name, age)
// Выведет: Kim is 22 years old.
}
Println
func Println(a ...any) (n int, err error)
Форматирует аргументы в формате по умолчанию и пишет в стандартный вывод. Пробелы добавляются всегда, в конце добавляется перенос строки. Возвращает количество записанных байт и ошибку записи, если она возникла.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
fmt.Println(name, "is", age, "years old.")
// По соглашению ошибку, возвращаемую Println, обычно игнорируют.
// Выведет: Kim is 22 years old.
}
Scan
func Scan(a ...any) (n int, err error)
Читает текст из стандартного ввода, сохраняя разделённые пробелами значения в последовательные аргументы. Переносы строк считаются пробелами. Возвращает количество успешно просканированных элементов. Если оно меньше числа аргументов — err сообщит причину.
Scanf
func Scanf(format string, a ...any) (n int, err error)
Читает текст из стандартного ввода, разбирая значения по строке формата. Возвращает количество успешно просканированных элементов. Если оно меньше числа аргументов — err сообщит причину. Переносы строк во вводе должны соответствовать переносам строк в формате. Исключение: глагол %c всегда читает следующую руну из ввода, даже если это пробел, табуляция или перенос строки.
Scanln
func Scanln(a ...any) (n int, err error)
Аналогична Scan, но останавливается на переносе строки. После последнего элемента должен быть перенос строки или EOF.
Sprint
func Sprint(a ...any) string
Форматирует аргументы в формате по умолчанию и возвращает результат как строку. Пробел между операндами добавляется только если ни один из них не является строкой.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
s := fmt.Sprint(name, " is ", age, " years old.")
fmt.Println(s)
// Выведет: Kim is 22 years old.
}
Sprintf
func Sprintf(format string, a ...any) string
Форматирует аргументы по строке формата и возвращает результат как строку.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
s := fmt.Sprintf("%s is %d years old.", name, age)
fmt.Println(s)
// Выведет: Kim is 22 years old.
}
Sprintln
func Sprintln(a ...any) string
Форматирует аргументы в формате по умолчанию и возвращает результат как строку. Пробелы добавляются всегда, в конце добавляется перенос строки.
package main
import (
"fmt"
)
func main() {
const name, age = "Kim", 22
s := fmt.Sprintln(name, "is", age, "years old.")
fmt.Print(s)
// Выведет: Kim is 22 years old.
}
Sscan
func Sscan(str string, a ...any) (n int, err error)
Читает значения из строки str, сохраняя разделённые пробелами элементы в последовательные аргументы. Переносы строк считаются пробелами. Возвращает количество успешно просканированных элементов. Если оно меньше числа аргументов — err сообщит причину.
Sscanf
func Sscanf(str string, format string, a ...any) (n int, err error)
Читает значения из строки str, разбирая их по строке формата. Возвращает количество успешно разобранных элементов. Переносы строк во вводе должны соответствовать переносам строк в формате.
package main
import (
"fmt"
)
func main() {
var name string
var age int
n, err := fmt.Sscanf("Kim is 22 years old.", "%s is %d", &name, &age)
if err != nil {
panic(err)
}
fmt.Println(n) // Выведет: 2
fmt.Println(name, age) // Выведет: Kim, 22
}
Sscanln
func Sscanln(str string, a ...any) (n int, err error)
Аналогична Sscan, но останавливается на переносе строки. После последнего элемента должен быть перенос строки или EOF.
Интерфейсы
Formatter
type Formatter interface {
Format(f State, verb rune)
}
Реализуется любым типом, имеющим метод Format. Реализация сама управляет интерпретацией State и глагола, и может вызывать Sprint, Fprint(f) и т.д. для формирования вывода.
GoStringer
type GoStringer interface {
GoString() string
}
Реализуется любым типом, имеющим метод GoString, определяющий Go-синтаксис для данного значения. Метод вызывается при форматировании значения глаголом %#v.
package main
import "fmt"
type Address struct {
City string
State string
Country string
}
type Person struct {
Name string
Age uint
Addr *Address
}
// GoString реализует интерфейс fmt.GoStringer
// и возвращает представление в синтаксисе Go.
func (p Person) GoString() string {
if p.Addr != nil {
return fmt.Sprintf("Person{Name: %q, Age: %d, Addr: &Address{City: %q, State: %q, Country: %q}}", p.Name, int(p.Age), p.Addr.City, p.Addr.State, p.Addr.Country)
}
return fmt.Sprintf("Person{Name: %q, Age: %d}", p.Name, int(p.Age))
}
func main() {
p1 := Person{
Name: "Warren",
Age: 31,
Addr: &Address{
City: "Denver",
State: "CO",
Country: "U.S.A.",
},
}
p2 := Person{
Name: "Theia",
Age: 4,
}
fmt.Printf("%#v\n", p1)
// Выведет: Person{Name: "Warren", Age: 31, Addr: &Address{City: "Denver", State: "CO", Country: "U.S.A."}}
fmt.Printf("%#v\n", p2)
// Выведет: Person{Name: "Theia", Age: 4}
}
ScanState
type ScanState interface {
// ReadRune читает следующую руну (кодовую точку Unicode) из ввода.
// При вызове во время Scanln, Fscanln или Sscanln возвращает EOF
// после первого '\n' или при выходе за пределы заданной ширины.
ReadRune() (r rune, size int, err error)
// UnreadRune заставляет следующий вызов ReadRune вернуть ту же руну.
UnreadRune() error
// SkipSpace пропускает пробельные символы во вводе. Переносы строк
// обрабатываются в зависимости от выполняемой операции — подробнее
// в документации пакета.
SkipSpace()
// Token пропускает пробелы (если skipSpace равен true), затем возвращает
// последовательность рун c, удовлетворяющих f(c). Если f равен nil,
// используется !unicode.IsSpace(c) — токен содержит непробельные символы.
// Переносы строк обрабатываются в зависимости от операции.
// Возвращаемый срез указывает на общие данные, которые могут быть
// перезаписаны следующим вызовом Token, функции сканирования с тем же
// ScanState или при возврате из вызывающего метода Scan.
Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
// Width возвращает значение ширины и флаг её наличия.
// Единица измерения — кодовые точки Unicode.
Width() (wid int, ok bool)
// Поскольку ReadRune реализован через интерфейс, Read не должен
// вызываться функциями сканирования; корректная реализация ScanState
// вправе всегда возвращать ошибку из Read.
Read(buf []byte) (n int, err error)
}
ScanState представляет состояние сканера, передаваемое пользовательским сканерам. Сканер может читать ввод руна за руной или запрашивать у ScanState следующий токен, ограниченный пробелами.
Scanner
type Scanner interface {
Scan(state ScanState, verb rune) error
}
Реализуется любым типом, имеющим метод Scan, который читает из ввода представление значения и сохраняет результат в получателе — получатель должен быть указателем. Метод вызывается для любого аргумента функций Scan, Scanf или Scanln, реализующего данный интерфейс.
State
type State interface {
// Write — функция для записи форматированного вывода.
Write(b []byte) (n int, err error)
// Width возвращает значение ширины и флаг её наличия.
Width() (wid int, ok bool)
// Precision возвращает значение точности и флаг её наличия.
Precision() (prec int, ok bool)
// Flag сообщает, установлен ли флаг c (символ).
Flag(c int) bool
}
State представляет состояние принтера, передаваемое пользовательским форматтерам. Предоставляет доступ к интерфейсу io.Writer, а также к флагам и параметрам спецификатора формата операнда.
Stringer
type Stringer interface {
String() string
}
Реализуется любым типом, имеющим метод String, определяющий «родной» формат значения. Метод вызывается при форматировании значения любым глаголом, принимающим строку, или при неформатированном выводе, например через Print.
package main
import "fmt"
// Animal содержит название животного и количество ног.
type Animal struct {
Name string
Legs int
}
// String реализует интерфейс fmt.Stringer.
func (a Animal) String() string {
return fmt.Sprintf("%v (%d)", a.Name, a.Legs)
}
func main() {
zebra := Animal{"Gopher", 2}
fmt.Println(zebra)
// Выведет: Gopher (2)
}
Итоги
Append*— добавляют результат к срезу байт (с Go 1.19)Errorfподдерживает%wдля оборачивания ошибок; несколько%wвернут[]errorчерезUnwrapFprint*/Fprintf*/Fprintln*пишут вio.Writerи возвращают(n int, err error)Print*/Printf*/Println*пишут вos.StdoutSprint*/Sprintf*/Sprintln*возвращают строкуFscan*/Scan*/Sscan*— сканирование изio.Reader, stdin и строки соответственноStringer(String() string) — автоматически вызывается при выводе;GoStringer(GoString() string) — при%#vFormatterпозволяет полностью управлять форматированием через методFormat(State, rune)Scannerпозволяет типу самому управлять разбором ввода через методScan(ScanState, rune)
Предыдущий шаг: Пакет fmt (часть 2)