博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[golang]-go中字符串格式化与fmt包简介
阅读量:2056 次
发布时间:2019-04-28

本文共 6062 字,大约阅读时间需要 20 分钟。

文章目录

fmt包中实现了格式化的I/O函数(类似C语言中的printf和scanf,但更加简单)。字符串相关操作参见《》。

格式化符

对于复杂类型,默认按以下规则打印:

  • struct: {field0 field1 …}
  • array, slice: [elem0 elem1 …]
  • maps: map[key1:value1 key2:value2 …]
  • pointer to above: &{}, &[], &map[]

通用

通用的格式化符:

  • %v:值的默认格式,变量的自然形式(natural format);
  • %+v:当打印结构体时,输出结构体成员名与值;
  • %#v:当打印结构体时,输出结构体类型名、成员名与值
  • %T:打印类型(相应值的类型);
  • %%:打印百分号;
type ListNode struct {
Val int Next *ListNode}tmp := ListNode{
Val: -1, Next: nil,}fmt.Printf(" %v \n %+v \n %#v \n %T \n", tmp, tmp, tmp, tmp)// {-1
}// {Val:-1 Next:
}// ListNode{Val:-1, Next:(*ListNode)(nil)}// ListNode

指针

地址格式化符:

  • %p:打印指针的地址(以0x开始);对于切片打印首个元素的地址;
sl := []int{
1,2,3}fmt.Printf(" %v \n %+v \n %#v \n %p \n", sl, sl, sl, sl)// [1 2 3]// [1 2 3]// []int{1, 2, 3}// 0xc00000c3a0

数值

布尔类型:

  • %t:打印true 或 false

整数:

  • %b:二进制表示
  • %c:相应Unicode码点所表示的字符
  • %d:十进制表示
  • %o:八进制表示
  • %q:单引号围绕的字符字面值
  • %x:十六进制表示,字母形式为小写 a-f
  • %X:十六进制表示,字母形式为大写 A-F
  • %U:Unicode格式:U+1234,等同于 “U+%04X”

%q格式化符:

n := 65ch := '字's := "字符"fmt.Printf("%q, %q, %q\n", n, ch, s)// 'A', '字', "字符"

浮点与复数:

  • %b:指数为2的幂的科学计数法,与 strconv.FormatFloat中的 ‘b’ 转换格式一致。例如 -123456p-78
  • %e:科学计数法,例如 -1234.456e+78
  • %E:科学计数法,例如 -1234.456E+78
  • %f:有小数点而无指数,例如 123.456
  • %g:根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出
  • %G:根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出

字符串与字节序列

字符串与byte切片:

  • %s:字符串或切片的无解译字节;
  • %q:双引号围绕的字符串;
  • %x:十六进制,小写字母,每字节两个字符;
  • %X:十六进制,大写字母,每字节两个字符;
s := "字符"fmt.Printf("%v, %q, %s, %x, % x\n", s, s, s, s, s)sl := []byte{
65, 74, 77}fmt.Printf("%v, %q, %s, %X, % X\n", sl, sl, sl, sl, sl)// 字符, "字符", 字符, e5ad97e7aca6, e5 ad 97 e7 ac a6// [65 74 77], "AJM", AJM, 414A4D, 41 4A 4D

宽度与精度

  • 宽度:通过百分号后面的十进制数指定;若未指定宽度,表示除必需之外不作填充;
  • 精度(可能有):宽度后跟点号后跟的十进制数指定;若未指定精度,则使用默认精度;如果点号后没有跟数字,表示精度为0。
%f     default width, default precision%9f    width 9, default precision%.2f   default width, precision 2%9.2f  width 9, precision 2%9.f   width 9, precision 0

标识符

标识符与填充符号:

  • +: 总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义);
  • -: 在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐);
  • #: 切换格式;
    八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p);
    对%q(%#q),如果strconv.CanBackquote返回真会输出反引号括起来的未转义字符串;
    对%U(%#U),如果字符是可打印的,会在输出Unicode格式、空格、单引号括起来的go字面值;
  • (空格): 对于数值,正数前加空格而负数前加负号;对于字符串采用%x或%X时(% x或% X)会给各打印的字节之间加空格;
  • 0: 使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面;
ch := '字'fmt.Printf("%q, %+q\n", ch, ch)s := "字符"fmt.Printf("%q, %+q\n", s, s)// '字', '\u5b57'// "字符", "\u5b57\u7b26"

占位符

go支持显示参数占位符,通过在输出格式中指定其输出的顺序即可;参数从1开始,使用中括号括起来。

宽度与精度中的*可通过后面参数替换。

fmt.Printf("%[2]d, %[1]d\n", 11, 22)  //22, 11fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6)// 等价于:fmt.Sprintf("%6.2f", 12.0)

格式化错误

所有格式化错误(如将一个字符串提供给%d),都会输出一个以“%!”开始的错误信息,后跟错误内容。

var i int = 1fmt.Printf("%s\n", i)  //%!s(int=1)

GoStringer & Stringer

Stringer接口包含String()方法;任何类型只要定义了String()方法,就相当于定制了输出(类似C#等中的toString);通过print直接输出或%v输出时,就调用此定制输出:

type Stringer interface {
String() string}

而GoStringer接口包含了GoString()方法,用于定制%#v的格式化输出:

type GoStringer interface {
GoString() string}

以定制struct的输出为例:

type Animal struct {
Name string Age uint}// Stringer interface: “native” format for that valuefunc (a Animal) String() string {
return fmt.Sprintf("Stringer: %v (%d)", a.Name, a.Age)}// GoStringer interface: Go syntax for that value (%#v format)func (a Animal) GoString() string {
return fmt.Sprintf("GoStringer: %v (%d)", a.Name, a.Age)}func TestFormat() {
a := Animal{
Name: "Gopher", Age: 2, } fmt.Printf("%v, %#v\n", a, a) // Stringer: Gopher (2), GoStringer: Gopher (2) fmt.Println(a) // Stringer: Gopher (2)// 若不定制(即不实现String与GoString),则输出会如下// {Gopher 2}, format.Animal{Name:"Gopher", Age:0x2}// {Gopher 2}}

Scanning

一组读取格式化文本获取值的函数:

  • Scan、Scanf和Scanln从标准输入os.Stdin中读取;
  • Fscan、Fscanf和Fscanln从指定的io.Reader中读取;
  • Sscan、Sscanf和Sscanln从字符串中读取。

Scanln、Fscanln和Sscanln在读取到换行时停止,并要求一次提供一行所有条目;Scanf、Fscanf和Sscanf只有在格式化文本末端有换行时会读取到换行为止,其它函数则将换行符视为空格;Scanf、Fscanf、Sscanf会根据格式字符串解析参数,类似Printf。

要定制自定义格式化输入的类型需要实现Scanner接口:

// Scanner 由自定义类型实现,用于实现该类型的自定义扫描过程。// 当扫描器需要解析该类型的数据时,会调用其 Scan 方法。type Scanner interface {
// state 用于获取占位符中的宽度信息,也用于从扫描器中读取数据进行解析。 // verb 是占位符中的动词 Scan(state ScanState, verb rune) error}// 由扫描器(Scan 之类的函数)实现,用于给自定义扫描过程提供数据和信息。type ScanState interface {
// ReadRune 从扫描器中读取一个字符,如果用在 Scanln 类的扫描器中, // 则该方法会在读到第一个换行符之后或读到指定宽度之后返回 EOF。 // 返回“读取的字符”和“字符编码所占用的字节数” ReadRune() (r rune, size int, err error) // UnreadRune 撤消最后一次的 ReadRune 操作, // 使下次的 ReadRune 操作得到与前一次 ReadRune 相同的结果。 UnreadRune() error // SkipSpace 为 Scan 方法提供跳过开头空白的能力。 // 根据扫描器的不同(Scan 或 Scanln)决定是否跳过换行符。 SkipSpace() // Token 用于从扫描器中读取符合要求的字符串, // Token 从扫描器中读取连续的符合 f(c) 的字符 c,准备解析。 // 如果 f 为 nil,则使用 !unicode.IsSpace(c) 代替 f(c)。 // skipSpace:是否跳过开头的连续空白。返回读取到的数据。 // 注意:token 指向共享的数据,下次的 Token 操作可能会覆盖本次的结果。 Token(skipSpace bool, f func(rune) bool) (token []byte, err error) // Width 返回占位符中的宽度值以及宽度值是否被设置 Width() (wid int, ok bool) // 因为上面实现了 ReadRune 方法,所以 Read 方法永远不应该被调用。 // 一个好的 ScanState 应该让 Read 直接返回相应的错误信息。 Read(buf []byte) (n int, err error)}

Printing

一组格式化输出的函数:

  • Print、Println和Printf:将各参数格式化到标准输出os.Stdout;
  • Fprint、Fprintln和Fprintf:将各参数格式化到io.Writere中;
  • Sprint、Sprintln和Sprintf:将各参数格式化到字符串;

要定制自定义格式化输出的类型需要实现Formatter接口:

// Formatter 由自定义类型实现,用于实现该类型的自定义格式化过程。// 当格式化器需要格式化该类型的变量时,会调用其 Format 方法。type Formatter interface {
// f 用于获取占位符的旗标、宽度、精度等信息,也用于输出格式化的结果 // c 是占位符中的动词 Format(f State, c rune)}// 由格式化器(Print 之类的函数)实现,用于给自定义格式化过程提供信息type State interface {
// Formatter 通过 Write 方法将格式化结果写入格式化器中,以便输出。 Write(b []byte) (ret int, err error) // Formatter 通过 Width 方法获取占位符中的宽度信息及其是否被设置。 Width() (wid int, ok bool) // Formatter 通过 Precision 方法获取占位符中的精度信息及其是否被设置。 Precision() (prec int, ok bool) // Formatter 通过 Flag 方法获取占位符中的旗标[+- 0#]是否被设置。 Flag(c int) bool}

Errorf

go中的返回错误都通过error来表示,errors.New和fmt.Errorf函数用于创建实现error接口的错误对象:

type error interface {
Error() string}

Errorf功能与Sprintf类似,但将格式化结果字符串包装成error返回,以方便生成所需的error错误类型。

func Dived(i int, j int) (r int, err error) {
if j == 0 {
err = fmt.Errorf("param-2 can not %d", j) return } return i / j, err }

转载地址:http://gwilf.baihongyu.com/

你可能感兴趣的文章
红帽宣布发布企业容器仓库开源项目 Quay
查看>>
跨平台构建 Docker 镜像新姿势,x86、arm 一把梭
查看>>
k8s v1.17 新特性预告: 拓扑感知服务路由
查看>>
彻底理解矩阵乘法
查看>>
使用 buildx 构建多平台 Docker 镜像
查看>>
Kubelet 中的 “PLEG is not healthy” 到底是个什么鬼?
查看>>
不懂OpenShift,不足以谈云计算!
查看>>
别让自己“墙”了自己
查看>>
让你的网站用上炫酷的中文字体
查看>>
使用 font-spider 对 webfont 网页字体进行压缩
查看>>
云原生服务网格 Istio 1.4 部署指南
查看>>
让 Linux 防火墙新秀 nftables 为你的 VPS 保驾护航
查看>>
Istio 1.4 部署指南
查看>>
贫苦家庭用户的 Envoy xDS 控制平面
查看>>
Kubernetes Pod 网络精髓:pause 容器详解
查看>>
Docker 技术鼻祖 Linux Namespace 入门系列:Namespace API
查看>>
使用 ebpf 深入分析容器网络 dup 包问题
查看>>
Kubelet 中的 “PLEG is not healthy” 到底是个什么鬼?
查看>>
超详细的网络抓包神器 Tcpdump 使用指南
查看>>
从 Kubernetes 资源控制到开放应用模型,控制器的进化之旅
查看>>