fmt.Scanln 期望换行错误

huangapple go评论81阅读模式
英文:

fmt.Scanln expected newline error

问题

我正在尝试学习Go语言,但在这个问题上遇到了困难:http://ideone.com/hbCamr 或 http://ideone.com/OvRw7t

package main
import "fmt"

func main(){
  var i int
  var f float64
  var s string

  _, err := fmt.Scan(&i)
  if err == nil {
    fmt.Println("读取到一个整数:", i)
  } else {
    fmt.Println("错误:", err)
  }

  _, err = fmt.Scan(&f)
  if err == nil {
    fmt.Println("读取到一个浮点数:", f)
  } else {
    fmt.Println("错误:", err)
  }
  _, err = fmt.Scan(&s)
  if err == nil {
    fmt.Println("读取到一个字符串:", s)
  } else {
    fmt.Println("错误:", err)
  }

  _, err = fmt.Scanln(&s)
  if err == nil {
    fmt.Println("读取到一行:", s)
  } else {
    fmt.Println("错误:", err)
  }
}

对于以下输入:

123
123.456
everybody loves ice cream

输出结果为:

读取到一个整数: 123
读取到一个浮点数: 123.456
读取到一个字符串: everybody
错误: Scan: expected newline

这是预期的行为吗?为什么它不像C++的getline函数那样工作?http://ideone.com/Wx8z5o

英文:

I'm trying to learn Go, but stuck with this one: http://ideone.com/hbCamr or http://ideone.com/OvRw7t

package main
import "fmt"

func main(){
  var i int
  var f float64
  var s string

  _, err := fmt.Scan(&i)
  if err == nil {
    fmt.Println("read 1 integer: ",i)
  } else {
    fmt.Println("Error: ",err)
  }

  _, err = fmt.Scan(&f)
  if err == nil {
    fmt.Println("read 1 float64: ",f)
  } else {
    fmt.Println("Error: ",err)
  }
  _, err = fmt.Scan(&s)
  if err == nil {
    fmt.Println("read 1 string: ",s)
  } else {
    fmt.Println("Error: ",err)
  }

  _, err = fmt.Scanln(&s)
  if err == nil {
    fmt.Println("read 1 line: ",s)
  } else {
    fmt.Println("Error: ",err)
  }
}

for this input:

123
123.456
everybody loves ice cream

the output was:

read 1 integer:  123
read 1 float64:  123.456
read 1 string:  everybody
Error:  Scan: expected newline

is this the expected behavior? why doesn't it work like C++ getline? http://ideone.com/Wx8z5o

答案1

得分: 11

答案在Scanln的文档中:

> Scanln与Scan类似,但在换行符处停止扫描,并且在最后一项之后必须有一个换行符或EOF。

Scan的行为也与文档中描述的一样:

> Scan从标准输入中扫描文本,将连续的以空格分隔的值存储到连续的参数中。换行符被视为空格。它返回成功扫描的项目数。如果成功扫描的项目数少于参数数目,err将报告原因。

总之:Scan将每个单词(由空格分隔的字符串)放入相应的参数中,将换行符视为空格。Scanln也是如此,但在换行符处停止解析,不再继续解析。

如果你想读取一行(以\n结尾),可以使用bufio.Reader及其ReadString方法:

line, err := buffer.ReadString('\n')
英文:

The answer is in the documentation of Scanln:

> Scanln is similar to Scan, but stops scanning at a newline and after the final item there must be a newline or EOF.

Scan behaves as documented as well:

> Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned. If that is less than the number of arguments, err will report why.

To conclude: Scan puts each word (a string separated by space) into a corresponding argument, treating newlines as space. Scanln does the same but treats newlines as a stop character, not parsing any further after that.

In case you want to read a line (\n at the end) use bufio.Reader and its ReadString method:

line, err := buffer.ReadString('\n')

答案2

得分: 1

作为解决方法,您可以实现自己的fmt.Scanner

package main
import "fmt"

type newline struct { tok string }

func (n *newline) Scan(state fmt.ScanState, verb rune) error {
   tok, err := state.Token(false, func(r rune) bool {
      return r != '\n'
   })
   if err != nil {
      return err
   }
   if _, _, err := state.ReadRune(); err != nil {
      if len(tok) == 0 {
         panic(err)
      }
   }
   n.tok = string(tok)
   return nil
}

func main() {
   var n newline
   fmt.Scan(&n)
   fmt.Println(n.tok)
}

https://golang.org/pkg/fmt#Scanner

英文:

As a workaround, you can implement your own fmt.Scanner:

package main
import "fmt"

type newline struct { tok string }

func (n *newline) Scan(state fmt.ScanState, verb rune) error {
   tok, err := state.Token(false, func(r rune) bool {
      return r != '\n'
   })
   if err != nil {
      return err
   }
   if _, _, err := state.ReadRune(); err != nil {
      if len(tok) == 0 {
         panic(err)
      }
   }
   n.tok = string(tok)
   return nil
}

func main() {
   var n newline
   fmt.Scan(&n)
   fmt.Println(n.tok)
}

https://golang.org/pkg/fmt#Scanner

huangapple
  • 本文由 发表于 2014年6月3日 09:46:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/24005899.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定