fmt包中跟scan相關的函數總共有9個,最基礎的Fscanf函數
Fscanf函數的聲明是
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
作用:Fscanf從r(即實現io.Reader接口的類型)掃描文本,根據format 參數指定的格式將成功讀取的空白分隔的值保存進成功傳遞給本函數的參數(注意 換行也是認爲空白分割的)。返回成功掃描的條目個數和遇到的任何錯誤。
例子:
var(
isOk bool
str string
)
len,err :=fmt.Fscanf(os.Stdin,"%t %s",&isOk,&str)
if err != nil{
fmt.Println(err)
}
fmt.Println("讀取到的長度",len) //讀取到的長度2
//假設終端輸入 t string\n
fmt.Println(isOk,str) //true string
在Fscanf函數上延伸的函數有
Scanf 與Fscanf的區別是從標準輸入掃描文本,實現過程如下:
func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
Sscanf 與Fscanf的區別是從字符串中掃面文本,實現過程如下:
type stringReader string
//實現io.Reader接口的方法
func (r *stringReader) Read(b []byte) (n int, err error) {
n = copy(b, *r)
*r = (*r)[n:]
if n == 0 {
err = io.EOF
}
return
}
//具體調用
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf((*stringReader)(&str), format, a...)
}
剩下三個 scan,Fscan,SScan與前面f後綴函數的區分是format格式類型不需要指定,系統會默認使用v格式(默認類型)
Fscanln,SScanln,scan與不含ln的函數區別是換行不是當着空白分割而是當做結束符
var(
is_ok bool
st string
)
_, err := fmt.Sscan("t\n string", &is_ok, &st)
if err != nil {
fmt.Println("錯誤:", err)
}
fmt.Println(is_ok, st) //輸出 true string
//
_, err := fmt.Sscanln("t\n string", &is_ok, &st)
if err != nil {
fmt.Println("錯誤:", err)
}
fmt.Println(is_ok, st)
//輸出
// 錯誤: unexpetced newline
// true
可以看到在Sscanln函數中碰到'\n'後面的字符串就不在解析了,即將\n當做了結束符,導致st變量需要的字符串獲取不到,報出了
unexpected newline的錯誤
具體在GO源碼中的流程是通過SkipSpace()函數處理的,該函數在每次掃描一個參數給變量前調用,用來先跳過一段空白字符,在這裏會決定\n是空白字符 還是結束符
func (s *ss) SkipSpace() {
for {
//掃描一個字符
r := s.getRune()
//如果是結束符退出函數
if r == eof {
return
}
//s.peek("\n")是表示 判斷當前讀取到的字符的下一個字符是否是\n
//這段意思是 如果當前字符 跟下個字符 拼成\r\n 就繼續向前掃描
if r == '\r' && s.peek("\n") {
continue
}
//我們主要看的是這裏,碰到一個\n時,是怎麼處理的
if r == '\n' {
//這裏可以看到如果s.nlIsSpace是ture時就當做空白字符
//有後綴ln的函數,就是將該變量設置成了false
//所以就拋出了下面的錯誤
if s.nlIsSpace {
continue
}
s.errorString("unexpected newline")
return
}
if !isSpace(r) {
s.UnreadRune()
break
}
}
}