1. fmt 包初识
在 fmt
包,有关格式化输入输出的方法就两大类:Scan
和 Print
,分别在scan.go 和 print.go 文件中。
print.go文件中定义了如下函数:
func Printf(format string, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Sprintf(format string, a ...interface{}) string
func Print(a ...interface{}) (n int, err error)
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Sprint(a ...interface{}) string
func Println(a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
func Sprintln(a ...interface{}) string
这9个函数,按照两个维度来说明,基本上可以说明白了。
- 如果把
Print
理解为核心关键字,那么后面跟的后缀有"f
"和"ln
"以及"",着重的是输出内容的最终结果;如果后缀是"f
", 则指定了format 如果后缀是"ln
", 则有换行符。
Println、Fprintln、Sprintln 输出内容时会加上换行符;
Print、Fprint、Sprint 输出内容时不加上换行符;
Printf、Fprintf、Sprintf 按照指定格式化文本输出内容。
- 如果把
Print
理解为核心关键字,那么前面的前缀有"F
"和"S
"以及"",着重的是输出内容的目标(终端);如果前缀是"F
", 则指定了io.Writer
如果前缀是"S
", 则是输出到字符串
Print、Printf、Println 输出内容到标准输出os.Stdout;
Fprint、Fprintf、Fprintln 输出内容到指定的io.Writer;
Sprint、Sprintf、Sprintln 输出内容到字符串。
scan.go文件中定义了如下函数:
func Scanf(format string, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
func Scan(a ...interface{}) (n int, err error)
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Sscan(str string, a ...interface{}) (n int, err error)
func Scanln(a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
这9个函数可以扫描格式化文本以生成值。同样也可以按照两个维度来说明。
- 如果把"
Scan
"理解为核心关键字,那么后面跟的后缀有"f
"和"ln
"以及"",着重的是输入内容的结果;如果后缀是"f
", 则指定了format 如果后缀是"ln
", 则有换行符
Scanln、Fscanln、Sscanln 读取到换行时停止,并要求一次提供一行所有条目;
Scan、Fscan、Sscan 读取内容时不关注换行;
Scanf、Fscanf、Sscanf 根据格式化文本读取。
- 如果把"
Scan
"理解为核心关键字,那么前面的前缀有"F
"和"S
"以及"",着重的是输入内容的来源(终端);如果前缀是"F
", 则指定了io.Reader
如果前缀是"S
", 则是从字符串读取
Scan、Scanf、Scanln 从标准输入os.Stdin读取文本;
Fscan、Fscanf、Fscanln 从指定的io.Reader接口读取文本;
Sscan、Sscanf、Sscanln 从一个参数字符串读取文本。
2. 格式化 verb 应用
2.1 通用
符号 | 含义 |
---|---|
%v |
值的默认格式表示。当输出结构体时,扩展标志(%+v )会添加字段名 |
%#v |
值的Go语法表示 |
%T |
值的类型的Go语法表示 |
%% |
百分号 |
type Person struct {
Name string
}
func main() {
person := Person{Name: "亚索"}
fmt.Printf("%v", person) //{亚索}
fmt.Printf("%+v", person) //{Name:亚索}
fmt.Printf("%#v", person) //main.Person{Name:"亚索"}
fmt.Printf("%T", person) //main.Person
fmt.Printf("%%") //%
}
2.2 布尔值
符号 | 含义 |
---|---|
%t |
单词true或false |
func main() {
fmt.Printf("%t", true) // true
fmt.Printf("%t", false) //false
}
2.3 整数
符号 | 含义 |
---|---|
%b |
表示为二进制 |
%c |
该值对应的unicode码值 |
%d |
表示为十进制 |
%o |
表示为八进制 |
%q |
该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示 |
%x |
表示为十六进制,使用a-f |
%X |
表示为十六进制,使用A-F |
%U |
表示为Unicode格式:U+1234,等价于"U+%04X" |
func main() {
fmt.Printf("%b", 5) // 101
fmt.Printf("%c", 0x4E2d) // 中
fmt.Printf("%d", 0x12) // 18
fmt.Printf("%o", 10) // 12
fmt.Printf("%q", 0x4E2d) // '中'
fmt.Printf("%x", 13) // d
fmt.Printf("%X", 13) // D
fmt.Printf("%U", 0x4E2d) // U+4E2D
}
2.4 浮点数与复数
符号 | 含义 |
---|---|
%b |
无小数部分、二进制指数的科学计数法,如-123456p-78;参见strconv.FormatFloat |
%e |
科学计数法,如-1234.456e+78 |
%E |
科学计数法,如-1234.456E+78 |
%f |
有小数部分但无指数部分,如123.456 |
%F |
等价于%f |
%g |
根据实际情况采用%e或%f格式(以获得更简洁、准确的输出) |
%G |
根据实际情况采用%E或%F格式(以获得更简洁、准确的输出) |
func main() {
fmt.Printf("%b", 10.20) // 5742089524897382p-49
fmt.Printf("%e", 10.20) // 1.020000e+01
fmt.Printf("%E", 10.20) // 1.020000E+01
fmt.Printf("%f", 10.20) // 10.200000
fmt.Printf("%F", 10.20) // 10.200000
fmt.Printf("%g", 10.20) // 10.2
fmt.Printf("%G", 10.20) // 10.2
}
2.5 字符串和 []byte
符号 | 含义 |
---|---|
%s |
直接输出字符串或者[]byte |
%q |
该值对应的双引号括起来的Go语法字符串字面值,必要时会采用安全的转义表示 |
%x |
每个字节用两字符十六进制数表示(使用a-f) |
%X |
每个字节用两字符十六进制数表示(使用A-F) |
func main() {
fmt.Printf("%s", []byte("Go语言")) // Go语言
fmt.Printf("%q", "Go语言") // "Go语言"
fmt.Printf("%x", "golang") // 676f6c616e67
fmt.Printf("%X", "golang") // 676F6C616E67
}
2.6 指针
符号 | 含义 |
---|---|
%p |
表示为十六进制,并加上前导的0x |
type Person struct {
Name string
}
func main() {
person := Person{Name: "瑞雯"}
fmt.Printf("%p",&person) // 0xc0000881e0
}
2.7 其他 flag
符号 | 含义 |
---|---|
+ |
总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义) |
- |
在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐) |
# |
切换格式:八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p); 对%q(%#q),如果strconv.CanBackquote返回真会输出反引号括起来的未转义字符串; 对%U(%#U),如果字符是可打印的,会在输出Unicode格式、空格、单引号括起来的Go字面值; |
0 |
使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面; |
verb会忽略不支持的旗标(flag)
type Person struct {
Name string
}
func main() {
person := Person{Name: "菲奥娜"}
fmt.Printf("%+q", "中文") // "u4e2du6587"
fmt.Printf("%#o", 46) // 056
fmt.Printf("%#x", 46) // 0x2e
fmt.Printf("%#p", &person) // c0000481f0
fmt.Printf("%#q", '中') // '中'
fmt.Printf("%#U", '中') // U+4E2D '中'
fmt.Printf("% d", 16) // 16
fmt.Printf("% x","abc") // 61 62 63
}
2.8 有效位输出
默认的 %f
输出格式是小数点后要有6位有效数字,不够补后置零
func main() {
fmt.Printf("%f
", 0.31415926) // 0.314159
fmt.Printf("%f
", 3.1415926) // 3.141593
fmt.Printf("%f
", 314.15926) // 314.159260
fmt.Printf("%f
", 3141.5926) // 3141.592600
fmt.Printf("%f
", 3141.) // 3141.000000
}
Go语言中对宽度和有效数字的限定:%[宽度].[精度]f
- 宽度是指整个浮点数的宽度,是指
整数位数+小数位数 + 1(小数点算一位)
,指定的宽度小于实际宽度或不指定宽度时,以实际宽度展示;当指定宽度大于实际宽度时,按照对齐方式和填充字符来填充 - 精度是指小数点后的数字个数,默认是6位,指定后按照指定的精度来,不足补后置零
func main() {
fmt.Printf("%3.3f
", 314.15926) // 314.159
fmt.Printf("%8.3f
", 314.15926) // 314.159
fmt.Printf("%8.f
", 314.15926) // 314
fmt.Printf("%4.0f
", 314.15926) // 314
fmt.Printf("%4.6f
", 314.15926) // 314.159260
}
对于整数 %d
,宽度和精度都表示整数数字个数,只是在指定宽度超过实际宽度时,指定精度会补前置零,指定宽度会按照实际宽度输出
func main() {
fmt.Printf("%d
", 12345) // 12345
fmt.Printf("%3d
", 12345) // 12345
fmt.Printf("%.3d
", 12345) // 12345
fmt.Printf("%3.3d
", 12345) // 12345
fmt.Printf("%6d
", 12345) // 12345
fmt.Printf("%.6d
", 12345) // 012345
fmt.Printf("%6.6d
", 12345) // 012345
fmt.Printf("%8.7d
", 12345) // 0012345
}
指定精度会至少要显示出这么多宽度的数字,所以不足时补零到足够为止,这时候,如果指定的宽度大于精度,那么剩余的填充符就不一定是0了,要看实际设定是什么,默认是左边补空格
对于 %e
、%g
这些,类似,遇到百度。