Реализация интерфейса пакета golang fmt String(), Error(), Format(), GoString()

Go

Введение

Интерфейс golang очень широко используется, почти каждый пакет будет использовать этот интерфейс, а пакет fmt является одним из наиболее часто используемых. В реальной разработке необходимо определить стандартный вывод структуры с помощью String(), стандартный вывод ошибок Error(), форматированный вывод Format() и специальный GoString(). Далее описывается использование интерфейса, сценарии использования и замечания.

String()

type TestString struct {}
func (t TestString) String() string {
	return "我是String"
}
func main() {
    fmt.Println(TestString{})
}
我是String

Он относительно прост в использовании, если его структураString() stringможно вывести.
fmtСумка определит, есть лиfmt.Stringerинтерфейс, а затем вызов.
Обычно используется для вывода структур по умолчанию, например:

type Student struct {
	number int
 	realname string
	age int
}
func main() {
	stu := &Student{
		number: 1,
		realname: "王小明",
		age: 18,
	}
	fmt.Println(stu)
}
&{1 王小明 18}

Измените его на:

type Student struct {
	number int
 	realname string
	age int
}
func (t *Student) String() string {
	return fmt.Sprintf("学号: %d\n真实姓名: %s\n年龄: %d\n", t.number, t.realname, t.age)
}
func main() {
	stu := &Student{
		number: 1,
		realname: "王小明",
		age: 18,
	}
	fmt.Println(stu)
}
学号: 1
真实姓名: 王小明
年龄: 18

Почувствуйте себя выше в мгновение ока!!

Error


type TestError struct {}
func (t TestError) Error() string {
	return "我是Error"
}
func main() {
    fmt.Println(TestString{})
}
我是Error

На самом деле, как использоватьString()То же самое, но реализации нельзя заменять друг другом при разработке кода.
Наиболее распространенное использование - автономная упаковка.type XXXError struct{}, в конце статьи я постараюсь разобраться, почему он используется именно так.

Format

type TestFormat struct {}
func (t TestFormat) Format(s fmt.State, c rune) {
	switch c {
	case 'c':
		switch {
		case s.Flag('+'):
			fmt.Printf("我是+c\n")
		default:
			fmt.Fprint(s, "我是c\n")
		}
	default:
		fmt.Print("我是Format")
	}
}
func main() {
    t := TestFormat{}
    fmt.Println(t)
    fmt.Printf("%c\n", t)
    fmt.Printf("%+c\n", t)
    fmt.Printf("%s\n", t)
}
我是Format
我是c
我是+c
我是Format

fmt.PrintlnИнтерфейс Format также будет вызываться, поэтомуString() Format()не может находиться в одной структуре. Обычно используется сError()Аналогично, вы можете обратиться кgithub.com/pkg/errorsвнутреннийstack.goизfunc (f Frame) Format(s fmt.State, verb rune)

GoString

type TestGoString struct {}
func (t TestGoString) GoString() string {
	return "我是GoString"
}
func main() {
    t := TestGoString{}
    fmt.Println(TestGoString{})
    fmt.Printf("%s %#v\n", t, t)
}
{}
{} 我是GoString

Как показано вышеfmt.PrintlnМетод GoString не вызывается, только форматированием%#+ пометить вывод.
В случае отсутствия реализации интерфейса он обычно используется для вывода соответствующего значения по умолчанию, как показано ниже:

func main() {
	var i uint = 18
	// 输出十六进制
	fmt.Printf("%x\n", i)
	fmt.Printf("%#x\n", i)
}
12
0x12

Меры предосторожности

fmt/print.goизpp.handleMethods(verb rune) (handled bool)

func (p *pp) handleMethods(verb rune) (handled bool) {
	...
	// 判断Formatter
	if formatter, ok := p.arg.(Formatter); ok {
	    ...
	    formatter.Format(p, verb)
	    return
	}
    
        // 判断是否含有#标识符
	if p.fmt.sharpV {
	        // 判断GoStriner
		if stringer, ok := p.arg.(GoStringer); ok {
                        ...
			p.fmt.fmtS(stringer.GoString())
			return
		}
	} else {
		switch verb {
		case 'v', 's', 'x', 'X', 'q':
			switch v := p.arg.(type) {
			// 符合error接口
			case error:
                                ...
				p.fmtString(v.Error(), verb)
				return
                        // 符合Stringer接口
			case Stringer:
                                ...
				p.fmtString(v.String(), verb)
				return
			}
		}
	}
	return false
}

Формат -> (#) GoString -> ((v, s, x, X, q) Ошибка -> Строка) Все четыре интерфейса исходного кода управляются вызовом метода handlerMethods, они не независимы друг от друга и вызываются в соответствии с порядком приоритета. Поэтому дизайн интерфейса должен быть инкапсулирован как можно более независимо, чтобы избежать путаницы.

резюме

String()Для стандартного вывода в структуры и т.д.
Error()Метод инкапсуляции ошибок, вы можете изменить некоторые ошибки и выгрузить их в лог-систему или распечатать стек.
Format()заString()Расширенное использование для нескольких типов или форматов.
GoString()Часто используется для относительных значений.


Добро пожаловать к великим богам, чтобы общаться и направлять!