Go语言中三个输入函数(scanf,scan,scanln)的区别

Go语言中三个输入函数(scanf,scan,scanln)的区别

在 Go 语言中,fmt 包提供了三种输入函数:Scanf、Scan 和 Scanln。这三个函数都是用于从标准输入读取数据并存储到变量中,但是它们在处理输入的方式上有所不同。下面详细解读每个函数的特点和用法。

1. fmt.Scanf

  • 用法:fmt.Scanf(format string, a ...interface{}) (n int, err error)
  • 功能:根据格式化字符串 format 从标准输入读取数据,并将数据存储到提供的参数中。格式化字符串类似于 C 语言中的 scanf,例如 %d 表示读取一个整数,%s 表示读取一个字符串。
  • 输入终止条件:Scanf 读取输入时,会忽略空白字符,并且根据格式化字符串解析输入内容。输入可以包含换行符,但解析会按照格式字符串中的要求进行。

示例代码:

package main

import (
    "fmt"
)

func main() {
    var a int
    var b string
    fmt.Print("请输入一个整数和一个字符串(格式如:123 hello):")
    fmt.Scanf("%d %s", &a, &b) // 根据格式化字符串读取
    fmt.Println("整数:", a)
    fmt.Println("字符串:", b)
}
注意:
  • 如果输入的格式与指定的格式字符串不匹配,可能会导致读取失败或产生意外结果。

2. fmt.Scan

  • 用法:fmt.Scan(a ...interface{}) (n int, err error)
  • 功能:读取由空格分隔的输入数据,并将数据存储到提供的参数中。它不需要格式化字符串,而是依次将输入的值赋给传入的变量。
  • 输入终止条件:输入以空格或换行符为分隔符,读取的值必须与传入的参数数量匹配。

示例代码:

package main

import (
    "fmt"
)

func main() {
    var a int
    var b string
    fmt.Print("请输入一个整数和一个字符串(用空格分隔):")
    fmt.Scan(&a, &b) // 直接读取输入到变量中
    fmt.Println("整数:", a)
    fmt.Println("字符串:", b)
}
注意:
  • 输入数据必须能正确解析为指定的变量类型,否则会出现错误。
  • 如果输入的值数量与变量数量不匹配,程序会等待进一步的输入。

3. fmt.Scanln

  • 用法:fmt.Scanln(a ...interface{}) (n int, err error)
  • 功能:与 fmt.Scan 类似,但会在读取完所有指定的参数后检查是否有多余的输入。它要求读取的最后一个输入参数必须位于行的末尾,否则会返回一个错误。
  • 输入终止条件:读取到换行符结束,并要求读取的参数数量与传入的变量数量匹配。

示例代码:

package main

import (
    "fmt"
)

func main() {
    var a int
    var b string
    fmt.Print("请输入一个整数和一个字符串(用空格分隔,并按回车结束):")
    fmt.Scanln(&a, &b) // 读取输入到变量中,并检查换行
    fmt.Println("整数:", a)
    fmt.Println("字符串:", b)
}
注意:
  • 如果输入的值数量与传入的变量数量不匹配,或者在读取所有参数后还有多余的输入,则会返回错误。

总结比较

  • Scanf 更加灵活,可以指定格式,但要求输入格式必须匹配。
  • Scan 和 Scanln 更适合简单的输入读取,Scanln 还会检查是否有多余的输入。
    在实际应用中,根据需要选择适当的函数来读取用户输入。

这三种函数,都会将换行符,一起读取吗?

在 Go 语言中,fmt.Scanf、fmt.Scan 和 fmt.Scanln 这三个函数处理换行符的方式有所不同。让我们详细解释它们对换行符的处理:

1. fmt.Scanf

  • 换行符处理:Scanf 不会将换行符视为特殊的输入结束标记,它会根据指定的格式化字符串来解析输入数据。
  • 输入中包含换行符:如果换行符符合格式化字符串的要求,它会被视为空白字符而被忽略,否则会被保留在输入流中等待下一次读取

示例:

var a int
var b string
fmt.Print("请输入一个整数和一个字符串(如:123 hello):")
fmt.Scanf("%d %s", &a, &b) // 如果输入 "123\nhello",换行符会被忽略

在这个例子中,输入时如果用户输入 "123\nhello",换行符会被忽略,因为它只是分隔了两个数据。

2. fmt.Scan

  • 换行符处理:Scan 将换行符视为空白字符,与空格一样被忽略。它会继续读取输入,直到满足所有变量的赋值。
  • 连续输入的情况:即使输入中有换行符,Scan 仍然会尝试从输入流中读取更多的数据,直到满足要求的变量数量。

示例:

var a int
var b string
fmt.Print("请输入一个整数和一个字符串(用空格分隔):")
fmt.Scan(&a, &b) // 如果输入 "123\nhello",换行符会被忽略

在这个例子中,输入 "123\nhello" 时,Scan 会忽略换行符并继续读取输入,直到读取到字符串 "hello"。

3. fmt.Scanln

  • 换行符处理:Scanln 会将换行符作为输入的结束标志。当所有的输入参数都读取完毕后,Scanln 要求输入流中不能有多余的数据。如果有多余的数据,即使是换行符,也会返回错误。
  • 换行符终止:它要求最后一个输入参数之后必须是换行符,否则会报错。

示例:

var a int
var b string
fmt.Print("请输入一个整数和一个字符串(用空格分隔,并按回车结束):")
fmt.Scanln(&a, &b) // 如果输入 "123 hello\n",换行符作为结束标志

在这个例子中,输入 "123 hello\n" 时,Scanln 会正常读取到整数和字符串,并认为换行符是输入的结束标志。

总结

  • Scanf:根据格式化字符串解析输入,换行符如果不影响解析会被忽略。
  • Scan:将换行符视为空白字符,会继续读取更多数据,直到满足所有变量的赋值要求。
  • Scanln:以换行符作为输入结束标志,如果在所有参数读取完毕后还有多余输入(除了换行符),会返回错误。
    换行符是否被读取取决于函数的设计和用法,Scanln 是唯一一个明确要求换行符作为结束标志的函数。

输入中包含换行符:如果换行符符合格式化字符串的要求,它会被视为空白字符而被忽略,否则会被保留在输入流中等待下一次读取。

对上面加粗部分的解释:

为了更好地理解 fmt.Scanf 如何处理输入中的换行符,下面举一个具体的例子来说明这种行为。

例子

package main

import (
    "fmt"
)

func main() {
    var a int
    var b string

    fmt.Print("请输入一个整数和一个字符串(格式:123 hello):")
    fmt.Scanf("%d %s", &a, &b)
    fmt.Println("a:", a)
    fmt.Println("b:", b)
}

示例 1:输入 "123 hello\n"

  • 输入内容:123 hello,然后按下 Enter(实际上输入的是 "123 hello\n")。
  • 执行过程:

a.fmt.Scanf("%d %s", &a, &b) 尝试按格式化字符串 %d %s 解析输入数据。

b.%d 匹配到整数部分,读取 123,成功解析并赋值给变量 a。

c.%s 匹配到字符串部分,读取 hello,成功解析并赋值给变量 b。

d.剩余的换行符 \n 被 Scanf 视为分隔符(空白字符)而忽略掉。

结果:

  • 输出:

    a: 123
    b: hello

示例 2:输入 "123\nhello"

  • 输入内容:123,按下 Enter 键(输入 "123\n"),然后再输入 hello 并按下 Enter。
  • 执行过程:

a.fmt.Scanf("%d %s", &a, &b) 首先尝试解析 %d,从输入 "123\n" 中读取到整数 123 并赋值给 a。

b.接下来,fmt.Scanf 尝试读取 %s,但此时输入流中的字符是换行符 \n,它不符合字符串的格式要求。因此,Scanf 读取 %s 的尝试失败,换行符 \n 被保留在输入流中等待下一次读取。

c.因为读取 %s 失败,b 没有被赋值,程序继续等待下一个输入。

d.当用户再输入 hello 并按下 Enter 后,Scanf 成功读取到字符串 hello 并赋值给 b。

结果:

  • 输出:

    a: 123
    b: hello

解释

在示例 1 中,"123 hello\n" 中的换行符被视为空白字符,符合格式化字符串的要求,因此被忽略。而在示例 2 中,"123\nhello" 中的换行符不符合 %s 的格式要求,导致 Scanf 读取失败,换行符保留在输入流中,等待下一次读取。

这展示了 fmt.Scanf 处理换行符的两种情况:符合格式时忽略,不符合时保留在输入流中。

相关推荐
DEARM LINER12 分钟前
mysql 巧妙的索引
数据库·spring boot·后端·mysql
IronmanJay1 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
OT.Ter1 小时前
【力扣打卡系列】二分查找(搜索旋转排序数组)
算法·leetcode·职场和发展·go·二分查找
加载中loading...2 小时前
Linux线程安全(二)条件变量实现线程同步
linux·运维·服务器·c语言·1024程序员节
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
开心工作室_kaic3 小时前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
代码吐槽菌3 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
biomooc3 小时前
R语言 | paletteer包:拥有2100多个调色板!
r语言·数据可视化·1024程序员节
Hello.Reader3 小时前
FFmpeg 深度教程音视频处理的终极工具
ffmpeg·1024程序员节
Y.O.U..4 小时前
STL学习-容器适配器
开发语言·c++·学习·stl·1024程序员节