前段时间一直弄不清scanf、scan、scanln三个函数在使用场景和使用细节上的差别,这里我整理了一下
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
fmt.Scanf("%s", &name)
fmt.Scanf("%d", &age)
//fmt.Scanf("%s %d", &name, &age) 对于scanf,这句话等价于上面两句话
fmt.Println(name, " ", age)
}
这两种写法都一样,如果我要把名字和年龄分两行输入是不行的,运行结果就像这样:
第一种输入方法(一次性输入):
第二种输入方法(把名字和年龄分两次输入):
可以看到第二种情况age没有被赋值
这是为什么呢?
我们看看scanf的函数原型
其实scanf两个返回值n和err,n是按指定格式成功输入数据的个数,err是读取过程中遇到的错误,如果没有错误,err的值就为nil
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
n, err := fmt.Scanf("%s %d", &name, &age) //用n,err分别接受scanf扫描成功的个数和错误返回值
if err == nil{ //如果没有错误就输出name和age的值
fmt.Println(name, " ", age)
}else{
fmt.Println("读取成功",n, "个","错误:",err)
}
}
可以看到,我们只成功输入了bob这一个数据,有一个错误叫unexpected newline,这个错误其实就是我们输入的回车,因为scanf函数遇到scanf就结束,从缓冲区依次读取以空格分开的数据;对我们这个程序而言,首先按%s读入了bob,然后再按%d读取下一个数据(回车),但是回车键不是十进制整形数据,它按%d怎么可能读得进去呢,所以就出现了只成功读取一个数据,报错为 “没有意料到的新行”
首先,它们的函数原型
跟scanf差不多,都是有两个返回值,一个是读取成功个数,另一个是错误值
但是如果像刚刚那样用会发生什么
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
n, err := fmt.Scan(&name, &age) //用n,err分别接受scanf扫描成功的个数和错误返回值
/*n, err := fmt.Scan(&name)
n, err = fmt.Scan(&age)*/ //对于scan这种写法也等价于上面那种写法
if err == nil{ //如果没有错误就输出name和age的值
fmt.Println("输出:", name, " ", age)
}else{
fmt.Println("读取成功",n, "个","错误:",err)
}
}
对于scan,我们是可以多个数据多行输入的
对于scanln,又有些不同了
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
n, err := fmt.Scanln(&name, &age) //这种写法的话必须把name和age一行输入,因为scanln是以回车为标志结束
n, err := fmt.Scanln(&name) //这样写就可以分两行输入name和age
n, err = fmt.Scanln(&age)
if err == nil{ //如果没有错误就输出name和age的值
fmt.Println("输出:", name, " ", age)
}else{
fmt.Println("读取成功",n, "个","错误:",err)
}
}
其实scanln再换行的时候会把缓冲区的回车也收走,但是scan和scanf不会,所以就导致了scanf不能分多行输入数据。但是scan却可以,它虽然没有收走缓冲区的回车符,但是不会把回车符读进去,遇到回车它会继续读取下一个数据,而scanf会按照我们给的格式(如%d去读取数据),但是肯定读不进去的,所以就读取失败了
下面有几个例子:
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
fmt.Scan(&name)// 把Scan换成Scanln就可以了
n, err := fmt.Scanf("%d", &age)
//原因:scan没有把第一行输入结束后的回车收走,导致scanf按%d的格式去读取回车符,那肯定读取失败啊
//而scanln会把第一行输入结束的回车符读走,scanf会按%的格式去读取我们后面输入的数据
if err == nil{
fmt.Println("输出:", name, " ", age)
}else{
fmt.Println("读取成功",n, "个","错误:",err)
}
}
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
fmt.Scan(&name)
fmt.Scanln()
fmt.Scanf("%d", &age)
}
}
}
```go
package main
import "fmt"
//假如我们要输入一个人的年龄和名字
func main() {
var name string
var age int8
fmt.Scan(&name)
fmt.Scanln()
fmt.Scanf("%d", &age)
}