文章目录
- [一、 格式化输出(Print家族)](#一、 格式化输出(Print家族))
-
- [1. 核心函数](#1. 核心函数)
- [2、 格式化占位符(常用)](#2、 格式化占位符(常用))
- [二、 格式化输入](#二、 格式化输入)
- 三、基于bufio读取数据
Go语言通过fmt
包提供强大的字符串格式化功能,支持输出格式化、输入解析及字符串操作。
场景 | 推荐函数 | 格式字符串示例 | 说明 |
---|---|---|---|
简单空格分隔输入 | Scan /Scanln |
- | 适用于姓名、年龄等简单数据 |
自定义格式输入 | Scanf |
%s:%d |
解析带分隔符的数据(如KV对) |
从字符串解析数据 | SScanf |
%d-%s |
处理日志、配置等字符串数据 |
读取整行(含空格) | bufio.Reader + SScan |
- | 先读取整行,再按需解析 |
一、 格式化输出(Print家族)
1. 核心函数
函数名 | 说明 |
---|---|
Print |
按原样输出值,用空格分隔,不换行 |
Println |
输出值并换行,自动添加换行符 |
Printf |
按指定格式输出(核心格式化函数) |
Sprintf |
格式化并返回字符串(不输出到控制台) |
Fprintf |
格式化并输出到io.Writer (如文件、网络连接) |
2、 格式化占位符(常用)
占位符 | 类型 | 说明 |
---|---|---|
%d |
整数 | 十进制表示(如 %03d 补零至3位) |
%s |
字符串 | 输出字符串(如 %-10s 左对齐,宽度10) |
%f |
浮点数 | 固定小数位(如 %.2f 保留2位小数) |
%t |
布尔值 | true /false |
%v |
通用 | 值的默认格式(结构体输出字段值,切片输出元素) |
%+v |
通用 | 结构体输出带字段名(如 {Name:Alice Age:25} ) |
%#v |
通用 | Go语法表示(如 "string" 、[]int{1,2,3} ) |
%T |
类型 | 输出类型(如 int 、[]string ) |
%% |
字面量 | 输出 % 符号 |
示例:格式化输出
go
package main
import "fmt"
func main() {
name := "Alice"
age := 25
score := 95.5
// 基础格式化
fmt.Printf("姓名:%s,年龄:%d,分数:%.1f\n", name, age, score)
// 输出:姓名:Alice,年龄:25,分数:95.5
// 宽度与对齐
fmt.Printf("|%10s|", name) // 右对齐,宽度10 → "| Alice|"
fmt.Printf("|%-10s|\n", name) // 左对齐,宽度10 → "|Alice |"
// 结构体格式化
type User struct { Name string; Age int }
user := User{"Bob", 30}
fmt.Printf("%+v\n", user) // 带字段名 → {Name:Bob Age:30}
fmt.Printf("%#v\n", user) // Go语法 → main.User{Name:"Bob", Age:30}
}
二、 格式化输入
fmt
包提供3组输入函数,用于从不同数据源读取数据:
Scan
家族 :从标准输入(os.Stdin
)读取SScan
家族:从字符串中读取Fscan
家族 :从io.Reader
(如文件、网络流)读取
1、Scan家族:标准输入
函数名 | 说明 |
---|---|
Scan |
按空格/换行符分割输入,换行符视为空格,读取到足够参数后停止 |
Scanln |
遇到换行符或EOF时停止,换行符作为终止符(非分隔符) |
Scanf |
按指定格式解析输入(支持自定义分隔符和格式) |
示例1:Scan(空格/换行分隔)
go
package main
import "fmt"
func main() {
scanExample()
}
func scanExample() {
var name string
var age int
fmt.Print("请输入姓名和年龄(空格或换行分隔):")
// 输入示例:"Tom\n20" 或 "Tom 20"
fmt.Scan(&name, &age) // 换行符视为空格,读取两个参数
fmt.Printf("姓名:%s,年龄:%d\n", name, age)
}
示例2:Scanln(换行终止)
go
func scanlnExample() {
var name string
var age int
fmt.Print("请输入姓名和年龄(换行分隔):")
// 输入示例:"Tom\n20"(换行分隔)
fmt.Scanln(&name, &age) // 遇到换行符停止,读取两个参数
fmt.Printf("姓名:%s,年龄:%d\n", name, age)
}
示例3:Scanf(自定义格式)
go
func scanfExample() {
var name string
var age int
fmt.Print("请输入姓名:年龄(如 Alice:25):")
// 格式字符串 "%s:%d" 匹配 "姓名:年龄" 格式
fmt.Scanf("%s:%d", &name, &age) // 分隔符为 ":"
fmt.Printf("姓名:%s,年龄:%d\n", name, age)
}
2、SScan家族:字符串输入
从字符串中解析数据,用法与Scan家族一致,仅数据源为字符串。
示例:SScanf(从字符串解析)
go
func sscanfExample() {
input := "Bob 30 male"
var name string
var age int
var gender string
// 格式字符串 "%s %d %s" 匹配 "姓名 年龄 性别"
fmt.Sscanf(input, "%s %d %s", &name, &age, &gender)
fmt.Printf("解析结果:姓名=%s,年龄=%d,性别=%s\n", name, age, gender)
// 输出:解析结果:姓名=Bob,年龄=30,性别=male
}
3、返回值处理
所有Scan函数返回两个值:
n int
:成功读取的参数数量err error
:错误信息(如类型不匹配、参数不足)
示例:错误处理
go
func scanErrorHandling() {
var age int
n, err := fmt.Scan(&age) // 输入非整数(如 "abc")
if err != nil {
fmt.Printf("读取失败:%v\n", err) // 输出:invalid syntax
} else if n < 1 {
fmt.Println("未读取到有效数据")
} else {
fmt.Printf("成功读取年龄:%d\n", age)
}
}
三、基于bufio读取数据
我们可以从IO流中读取数据再配合Sscan 就完成了基于网络的Scan
这里采用bufio从标准输入读取数据, 真实案例你可以从Socket读取数据 发送过来
go
func readFullName() {
var (
name string
age uint
)
fmt.Print("请输入你的姓名和年龄, 以空格分隔: ")
stdin := bufio.NewReader(os.Stdin)
line, _, err := stdin.ReadLine()
if err != nil {
panic(err)
}
n, err := fmt.Sscanln(string(line), &name, &age)
if err != nil {
panic(err)
}
fmt.Printf("read number of items: %d", n)
fmt.Println()
fmt.Printf("姓名: %s 年龄: %d", name, age)
fmt.Println()
/**
请输入你的姓名和年龄, 以空格分隔: gaoliang 222
read number of items: 2
姓名: gaoliang 年龄: 222
*/
}