You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
这些 flag 值在代码实现的时候都是布尔值的形式存在的,当需要打印的时候,对于某些类型的打印方法,内部会根据这些 flag 值来做 if...else 判断,从而打印出不同的形式。fmt 包里面会有很多对于这个 flag 值的检查,像 map,struct,point 或者 interface 之类的会打印出它们类型的名字,然后才打印每个字段对应的值。
fmt 包应该是我们学习 golang 最开始接触的包,它是用于格式化我们的输入输出流的。但是一开始接触会对于代码中一会使用 fmt.Println 一会使用 fmt.Printf 有些困惑,而且各种占位符会让人非常迷惑。也许深入研究下 fmt 包可以有效地解开这个困惑。
Print
Print 函数不接受任何的格式化处理,直接将输入的参数值打印出来,但是注意的是,如果有多个参数值,那么如果该参数本身不是字符串并且前面不是字符串的情况下,会自动在前面加一个空格打印
Println
如上 Println 的函数签名所示,它接受任意类型的参数,然后将这个参数值打印出来。它的实现是:
可以看到,这里如果有多个参数,那么会自动在每个参数之间打印一个空格。在打印完所有参数之后,会打印一个换行符。
Printf
Printf 函数应该是最为复杂的一个格式化函数,它接收一个含有格式化标识符的字符串,然后将传入的参数对应的值写到字符串对应位置。
如果你想要打印对应变量的值和类型,那么就需要使用 %v 和 %T 这两个格式化符号。
位置引用
上面的代码你或许可以看出一点问题,如果我们想要同时打印一个变量的值和类型,我们就需要传入多次该变量吗?这样会显得非常麻烦,我们可以通过位置引用来做到多次使用一个变量。
位置的下标从 1 开始,通过方括号加上数字的形式来达到多次引用这个变量的值。
通用格式
我们可以看到 %v 可以打印出任意变量的值,在 fmt 底层的实现中,如果使用这个占位符,会使用类型推断来打印对应不同类型的值
而 %T 可以打印出变量对应的类型,它对应的底层实现其实就是利用反射 reflect.Typeof 这个函数获取类型:
宽度
在格式化输出的时候,fmt 还支持使用宽度设置:
如果像上面的这样,在输出 1 之前,会先输出 9 个空格。当然这个宽度是可以动态设置的:
这个时候 * 号代表的就是宽度,那么第一个传入的参数就是指定的宽度,这就代表比如如果你想输出多个字符串值,输出宽度需要根据每个字符串的长度来定的话,就可以使用这种形式。
flag
fmt 包有几个特定的前置 flag 来设置打印的模式:
具体可以看下下面的例子:
这些 flag 值在代码实现的时候都是布尔值的形式存在的,当需要打印的时候,对于某些类型的打印方法,内部会根据这些 flag 值来做 if...else 判断,从而打印出不同的形式。fmt 包里面会有很多对于这个 flag 值的检查,像 map,struct,point 或者 interface 之类的会打印出它们类型的名字,然后才打印每个字段对应的值。
比如 “#” 就是设置 fmt 模块上的 sharp 属性为 true,例如对于 map 类型,如果 sharp 值为 true,那么会打印出 map 类型的字面量类型,以下是具体实现代码:
精细化控制
如果你想精细化地控制你的输出,制定一些自己的规则,那么就可以实现 Formatter 接口,就好像在 Node.js 里面,自行定义 toJSON 方法,那么在变量值在 JSON.stringify 方法调用的时候,会按照你想要的方式进行打印。
Formatter & toJSON
类似 toJSON 方法,在 node 里面,你如果实现了对象的 toJSON 方法,那么在 JSON.stringify 方法调用的时候就会按照这个 toJSON 方法来打印,而在 golang 里面,也有类似的方法,在 fmt 包中提供了 Formatter 这一个接口,只要你的结构体实现了 Formatter 接口的 format 方法,那么在 print 等方法打印时使用它来对值的打印进行格式化。
比如需要转化一个结构体的某个属性值:
Stringer & toString
类似 toJSON,node 里面对于值的打印,如果对象实现了 toString 方法,那么在转化为字符串的时候会调用 toString 方法取方法的值进行返回。fmt 包对此也有类似功能,也就是 Stringer 接口,结构体需要实现 String 方法达到个性化地转化字符串时的值。
请看下面例子代码:结构体里面的 Sex 属性原本是数字类型,但是为了打印出来更语义化,所以想要对于值做一些替换
而对于 Formatter 和 Stringer 这两个接口,在 fmt 里面是 Formatter 优先级更高的,因为在实现的时候是先判断值是否符合 Formatter 接口即有没有实现 format 方法。
Sprint & Sprintln & Sprintf
这几个函数都和上面说的三个函数功能类似,只是这三个函数并不是将结果通过 io.stdout 输出,而是返回一个字符串。
Fprint & Fprintln & Fprintf
这三个函数的功能也和上面所说的函数类似,只是他们第一个接收的参数是一个输出流,如果知道 Node.js 的 stream 或者 shell 的重定向的同学应该知道,这个是 fmt 包提供用于重定向文件输出流的。
附录
go 居然也有 ...interface{}
如果函数声明了返回值,就直接用
The text was updated successfully, but these errors were encountered: