[系列]go源碼解讀,fmt —— 接口介紹

前言

fmt包實現了相似C語言printf和scanf的格式化I/O。格式化動做('verb')源自C語言但更簡單。本文將介紹 Stringer, GoStringer, State, Formatter這幾個接口的做用。python

Stringer 接口

type Stringer interface {
	String() string
}
複製代碼

若是一個對象實現了這個Stringer接口,那麼經過%s,%v打印,這時候會判斷這個對象是否實現了Stringer接口,若是實現了,就調用對象的String方法,怎麼感受有點像python中的 __str__ 方法。json

package main

import "fmt"

type person struct {
	Name string
	age int
}

func (p *person) String() string {
	return p.Name
}

func main() {
	p := &person{"jack",22}

	println(p)           // 0xc000090000,這個打印的是地址
	fmt.Println(p)       // jack
	fmt.Printf("%v\n",p) // jack
	fmt.Printf("%s\n",p) // jack
}

複製代碼

對於內建函數println() , print()是不能調用到String方法的。函數

對於某些結構體,當某些字段不但願在打印的時候輸出時,能夠實現 Stringer接口,達到隱藏某些字段的目的。學習

GoStringer 接口

type GoStringer interface {
	GoString() string
}
複製代碼

實現了GoStringer接口的對象,當採用 %#v格式化輸出時(其餘的形式會不會呢?),會調用GoString方法來生成輸出定義了該類型值的go語法表示。就是說這個是go特有的,好比&main.person{Name:"jack", age:22} 這種樣式的就是go語法來表示一個對象,固然咱們能夠本身定義。ui

package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	Name string
	age int
}

func (p *person) GoString() string {
	b, _ :=json.Marshal(p)
	return string(b)
}

func main() {
	p := &person{"jack",22}

	fmt.Printf("%v\n",p)    // &{jack 22}
	fmt.Printf("%#v\n",p)   // {"Name":"jack"} , GoString的輸出
	fmt.Printf("%+v\n",p)   // &{Name:jack age:22}
}
複製代碼

這裏咱們經過實現GoStringer接口,並返回對象 json 序列化後的字符串來達到改寫對象的go語法表示。spa

State 接口

type State interface {
    // Write方法用來寫入格式化的文本
    Write(b []byte) (ret int, err error)
    // Width返回寬度值,及其是否被設置
    Width() (wid int, ok bool)
    // Precision返回精度值,及其是否被設置
    Precision() (prec int, ok bool)
    // Flag報告是否設置了flag c(一個字符,如+、-、#等)
    Flag(c int) bool
}
複製代碼

在學習 State 接口以前,咱們先來看一下,go的格式化語法 code

% 表示格式化的開始位置orm

% 後面緊跟的+號,表示flagscdn

+ 後面的3.2表示寬度Width和精度Precision對象

f 爲佔位符 verb

那麼go格式化語法包括了 開始位置flags寬度精度佔位符 五個部分組成,State接口包含了其中三項信息。在解析格式化字符串的時候,會一個一個解析,當解析完成一個這樣的%+3.2f總體結構之後,數據保存到State,下一步調用printArg進行格式化,並將格式化後的數據寫入buffer,全部的結構解析完成以後寫入到io.Writer,並在控制檯輸出(後面會具體討論代碼是怎麼實現的)。

Formatter 接口

type Formatter interface {
	Format(f State, c rune)
}
複製代碼

Formatter 用於實現自定義格式化方法。可經過在自定義結構體中實現 Format 方法來實現這個目的。標準庫中使用在 /usr/local/go/src/fmt/print.go:580,會首先判斷結構體是否實現了 Formatter 接口,實現了則利用自定義 Formatter 格式化參數。未實現,則最大程度的利用 go語法格式 GoStringer 默認規則去格式化參數,其次是 errorStringer 接口。

咱們來看一下大廠 B站是怎麼實現這個接口的

// Format is a support routine for fmt.Formatter. It accepts the decimal
// formats 'd' and 'f', and handles both equivalently.
// Width, precision, flags and bases 2, 8, 16 are not supported.
func (x *Dec) Format(s fmt.State, ch rune) {
	if ch != 'd' && ch != 'f' && ch != 'v' && ch != 's' {
		fmt.Fprintf(s, "%%!%c(dec.Dec=%s)", ch, x.String())
		return
	}
	fmt.Fprintf(s, x.String())
}

複製代碼

是否是很簡單? 😝

小結

本小節介紹了fmt包中的幾個基礎接口和使用。下一篇,咱們將深刻fmt包的實現。

相關文章
相關標籤/搜索