当前位置:首页 > 尘凡 > 正文内容

Go的输出%使用

满纸空言3年前 (2021-11-02)尘凡27690

官方文档:https://pkg.go.dev/fmt

 

包 fmt 使用类似于 C 的 printf 和 scanf 的函数实现格式化的 I/O。“动词”格式源自 C,但更简单。

打印

动词:

一般的:

%v  打印结构时默认格式的值,加号标志 (%+v) 添加字段名称
%#v 值的 Go 语法表示
%T  值类型的 Go 语法表示
%%  文字百分号;不消耗任何价值

布尔值:

%t 真或假这个词

整数:

%b base 2 
%c 由相应的 Unicode 代码点表示的字符
%d base 10 
%o base 8 
%O base 8 with 0o prefix 
%q 一个单引号字符文字,用 Go 语法安全转义。
%x base 16,小写字母代表af 
%X base 16,大写字母代表AF 
%U Unicode 格式:U+1234;与“U+%04X”相同

浮点和复数成分:

%b 无小数点的科学记数法,指数为 2 的幂,
	以 strconv.FormatFloat 的方式使用 'b' 格式,
	例如 -123456p-78 
%e 科学记数法,例如 -1.234456e+78 
%E 科学记数法,例如 -1.234456 E+78 
%f 小数点但没有指数,例如 123.456 
%F %f 的同义词
%g %e 表示大指数,否则为 %f。下面讨论精度。
%G %E 表示大指数,%F 否则
%x 十六进制表示法(具有两个指数的十进制幂),例如 -0x1.23abcp+20 
%X 大写十六进制表示法,例如 -0X1.23ABCP+20

字符串和字节片(与这些动词同等对待):

%s 字符串或切片的未解释字节
%q 用 Go 语法安全转义的双引号字符串
%x base 16,小写,每字节两个字符
%X base 16,大写,每字节两个字符

片:

%p 以 16 进制表示的第 0 个元素的地址,前导 0x

指针:

%p base 16 表示法,带前导 0x 
%b、%d、%o、%x 和 %X 动词也适用于指针,
将值完全格式化为整数。

%v 的默认格式是:

bool: %t 
int, int8 等: %d 
uint, uint8 等: %d, %#x 如果用 %#v 
float32, complex64 等打印: %g
字符串: %s 
chan: %p
指针: %p

对于复合对象,元素使用这些规则递归打印,布局如下:

struct: {field0 field1 ...} 
array, slice: [elem0 elem1 ...] 
maps: map[key1:value1 key2:value2 ...]
指向上面的指针:&{}, &[], &map[]

宽度由紧接在动词之前的可选十进制数指定。如果不存在,则宽度是表示值所需的任何值。精度在(可选)宽度之后指定一个句点,后跟一个十进制数。如果不存在句点,则使用默认精度。没有以下数字的句点指定精度为零。例子:

%f 默认宽度,默认精度
%9f 宽度 9,默认精度
%.2f 默认宽度,精度 2 
%9.2f 宽度 9,精度 2 
%9.f 宽度 9,精度 0

宽度和精度以 Unicode 代码点为单位,即符文。(这与 C 的 printf 不同,后者的单位总是以字节为单位。)可以用字符 '*' 替换其中一个或两个标志,从而使它们的值从下一个操作数(在要格式化的操作数之前)获得,必须是 int 类型。

对于大多数值,宽度是要输出的最小符文数,如有必要,用空格填充格式化的表单。

然而,对于字符串、字节切片和字节数组,精度限制了要格式化的输入的长度(而不是输出的大小),必要时进行截断。通常它以符文来衡量,但对于这些类型,当使用 %x 或 %X 格式进行格式化时,它以字节为单位。

对于浮点值,width 设置字段的最小宽度,并且 precision 设置小数点后的位数(如果适用),除了 %g/%G precision 设置最大有效位数(删除尾随零) . 例如,给定 12.345 格式 %6.3f 打印 12.345 而 %.3g 打印 12.3。%e、%f 和 %#g 的默认精度为 6;对于 %g,它是唯一标识值所需的最小位数。

对于复数,宽度和精度独立应用于两个分量,结果用括号括起来,因此应用于 1.2+3.4i 的 %f 产生 (1.200000+3.400000i)。

其他标志:

+ 总是为数值打印一个符号;
	保证 %q (%+q) 的仅 ASCII 输出
- 在右侧而不是左侧填充空格(左对齐字段)
# 替代格式:添加前导 0b 表示二进制(%#b),0 表示八进制( %#o)、
	0x 或 0X 表示十六进制(%#x 或 %#X);为 %p (%#p) 抑制 0x; 
	对于 %q,如果 strconv.CanBackquote
	返回 true ,则打印原始(反引号)字符串;
	总是为 %e、%E、%f、%F、%g 和 %G 打印小数点;
	不要删除 %g 和 %G 的尾随零;
	如果字符可打印为 %U (%#U),则写例如 U+0078 'x'。
' ' (空格) 为省略号的数字留下一个空格 (% d); 
	在十六进制打印字符串或切片的字节之间放置空格 (% x, % X)
0 填充前导零而不是空格;
	对于数字,这会移动符号后面的填充

不期望它们的动词会忽略标志。例如,没有替代的十进制格式,因此 %#d 和 %d 的行为相同。

对于每个类似 Printf 的函数,还有一个不带格式的 Print 函数,相当于对每个操作数都说 %v。另一个变体 Println 在操作数之间插入空格并附加换行符。

不管动词如何,如果操作数是接口值,则使用内部具体值,而不是接口本身。因此:

var i interface{} = 23 
fmt.Printf("%v\n", i)

将打印 23。

除了使用动词 %T 和 %p 打印时,特殊格式注意事项适用于实现某些接口的操作数。按申请顺序:

1. 如果操作数是一个reflect.Value,则该操作数被它所持有的具体值替换,并且打印继续下一个规则。

2. 如果一个操作数实现了Formatter 接口,它将被调用。在这种情况下,动词和标志的解释由该实现控制。

3. 如果 %v 动词与 # 标志 (%#v) 一起使用并且操作数实现 GoStringer 接口,则将调用该接口。

如果格式(对于 Println 等隐式为 %v)对字符串有效(%s %q %v %x %X),则以下两条规则适用:

4. 如果操作数实现了错误接口,则会调用 Error 方法将对象转换为字符串,然后将其按照动词(如果有)的要求进行格式化。

5. 如果操作数实现了 String() 方法,则将调用该方法将对象转换为字符串,然后根据动词(如果有)的要求对其进行格式化。

对于切片和结构等复合操作数,该格式递归地应用于每个操作数的元素,而不是整个操作数。因此 %q 将引用字符串切片的每个元素,而 %6.2f 将控制浮点数组的每个元素的格式。

但是,当使用类似字符串的动词 (%s %q %x %X) 打印字节切片时,它被视为与字符串相同,作为单个项目。

为了避免递归,例如

type X string 
func (x X) String() string { return Sprintf("<%s>", x) }

在重复之前转换值:

func (x X) String() string { return Sprintf("<%s>", string(x)) }

无限递归也可以由自引用数据结构触发,例如包含自身作为元素的切片,如果该类型具有 String 方法。然而,这种病理很少见,并且包装不能防止它们。

打印结构时, fmt 不能,因此不会在未导出的字段上调用诸如 Error 或 String 之类的格式化方法。

显式参数索引

在 Printf、Sprintf 和 Fprintf 中,默认行为是每个格式化动词格式化调用中传递的连续参数。但是,紧接在动词之前的符号 [n] 表示将改为格式化第 n 个索引参数。用于宽度或精度的 '*' 之前的相同符号选择保存值的参数索引。处理括号表达式 [n] 后,后续动词将使用参数 n+1、n+2 等,除非另有指示。

例如,

fmt.Sprintf("%[2]d %[1]d\n", 11, 22)

将产生“22 11”,而

fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6)

相当于

fmt.Sprintf("%6.2f", 12.0)

将产生“12.00”。由于显式索引会影响后续动词,因此可以使用此表示法通过重置要重复的第一个参数的索引来多次打印相同的值:

fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)

将产生“16 17 0x10 0x11”。

格式错误

如果为动词提供了无效参数,例如向 %d 提供字符串,则生成的字符串将包含问题的描述,如以下示例所示:

错误类型或未知动词:%!verb(type=value) 
	Printf("%d", "hi"): %!d(string=hi)
参数太多:%!(EXTRA type=value) 
	Printf("hi ", "guys"): hi%!(EXTRA string=guys)
参数太少:%!verb(MISSING) 
	Printf("hi%d"): hi%!d(MISSING)
宽度或精度的非整数: %!(BADWIDTH) 或 %!(BADPREC) 
	Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi 
	Printf("%.*s", 4.5, "hi"): %! (BADPREC)hi
参数索引的使用无效或无效:%!(BADINDEX) 
	Printf("%*[2]d", 7): %!d(BADINDEX) 
	Printf("%.[2]d", 7) : %!d(BADINDEX)

所有错误都以字符串“%!”开头 有时后跟单个字符(动词),并以带括号的描述结尾。

如果 Error 或 String 方法在被打印例程调用时触发了恐慌, fmt 包会重新格式化来自恐慌的错误消息,并用它来自 fmt 包的指示来装饰它。例如,如果 String 方法调用 panic("bad"),则生成的格式化消息将如下所示

%!s(恐慌=坏)

%!s 仅显示发生故障时正在使用的打印动词。但是,如果恐慌是由错误或字符串方法的 nil 接收器引起的,则输出是未修饰的字符串“<nil>”。

扫描

一组类似的函数扫描格式化文本以产生值。Scan、Scanf 和 Scanln 从 os.Stdin 读取;Fscan、Fscanf 和 Fscanln 从指定的 io.Reader 读取;Sscan、Sscanf 和 Sscanln 从参数字符串中读取。

Scan、Fscan、Sscan 将输入中的换行符视为空格。

Scanln、Fscanln 和 Sscanln 在换行符处停止扫描,并要求项目后跟换行符或 EOF。

Scanf、Fscanf 和 Sscanf 根据格式字符串解析参数,类似于 Printf 的格式字符串。在接下来的文本中,“空格”表示除换行符之外的任何 Unicode 空白字符。

在格式字符串中,由 % 字符引入的动词消耗并解析输入;下面将更详细地描述这些动词。格式中除 %、空格或换行符之外的字符完全使用必须存在的输入字符。格式字符串中前面有零个或多个空格的换行符在输入中消耗零个或多个空格,后跟单个换行符或输入的结尾。格式字符串中换行符后面的空格会占用输入中的零个或多个空格。否则,格式字符串中任何一个或多个空格的运行都会在输入中消耗尽可能多的空格。除非格式字符串中的空格运行与换行符相邻,否则运行必须至少消耗输入中的一个空格或找到输入的结尾。

空格和换行符的处理与 C 的 scanf 系列的处理不同:在 C 中,换行符被视为任何其他空格,并且当格式字符串中的空格运行在输入中没有发现任何空格时,它永远不会出错。

动词的行为类似于 Printf 的动词。例如,%x 将扫描一个整数作为十六进制数,而 %v 将扫描该值的默认表示格式。Printf 动词 %p 和 %T 以及标志 # 和 + 未实现。对于浮点和复数值,所有有效的格式化动词(%b %e %E %f %F %g %G %x %X 和 %v)都是等价的,并且接受十进制和十六进制表示法(例如:“2.3 e+7", "0x4.5p-8") 和数字分隔下划线(例如:“3.14159_26535_89793”)。

动词处理的输入是隐式空格分隔的:除了 %c 之外的每个动词的实现都是通过丢弃剩余输入中的前导空格开始的,并且 %s 动词(和 %v 读入字符串)在第一个空格处停止消耗输入或换行符。

在扫描没有格式或带有 %v 动词的整数时,可以接受熟悉的基本设置前缀 0b(二进制)、0o 和 0(八进制)以及 0x(十六进制),数字分隔下划线也是如此。

宽度在输入文本中被解释,但没有用于精确扫描的语法(没有 %5.2f,只有 %5f)。如果提供了宽度,则在修剪前导空格后应用它,并指定要读取的最大符文数以满足动词。例如,

Sscanf(" 1234567 ", "%5s%d", &s, &i)

将 s 设置为 "12345" 并将 i 设置为 67 而

Sscanf(" 12 34 567 ", "%5s%d", &s, &i)

将 s 设置为“12”,将 i 设置为 34。

在所有扫描函数中,回车后紧跟换行符被视为普通换行符(\r\n 表示与 \n 相同)。

在所有的扫描函数中,如果一个操作数实现了 Scan 方法(即它实现了 Scanner 接口),该方法将用于扫描该操作数的文本。此外,如果扫描的参数数量少于提供的参数数量,则会返回错误。

要扫描的所有参数必须是指向基本类型的指针或 Scanner 接口的实现。

与 Scanf 和 Fscanf 一样,Sscanf 不需要消耗其全部输入。没有办法恢复 Sscanf 使用了多少输入字符串。

注意: Fscan 等可以读取超过它们返回的输入的一个字符(符文),这意味着调用扫描例程的循环可能会跳过某些输入。这通常只有在输入值之间没有空格时才会出现问题。如果提供给 Fscan 的阅读器实现了 ReadRune,则该方法将用于读取字符。如果读取器还实现了 UnreadRune,则该方法将用于保存字符并且连续调用不会丢失数据。要将 ReadRune 和 UnreadRune 方法附加到没有该功能的阅读器,请使用 bufio.NewReader。

扫描二维码推送至手机访问。

版权声明:本文由满纸空言发布,如需转载请注明出处。

本文链接:https://mzky.cc/post/69.html

分享给朋友:

“Go的输出%使用” 的相关文章

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。