fmt.Scanln期望换行错误

时间:2014-06-03 01:46:55

标签: input go

我正在尝试学习Go,但坚持使用这个:http://ideone.com/hbCamrhttp://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)
  }
}

输入:

123
123.456
everybody loves ice cream
输出是:

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

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

2 个答案:

答案 0 :(得分:6)

答案在documentation of Scanln

  

Scanln与“扫描”类似,但在换行符处停止扫描,在最终项目之后必须有换行符或EOF。

Scan的行为也是documented

  

扫描扫描从标准输入读取的文本,将连续的空格分隔值存储到连续的参数中。换行计为空格。它返回成功扫描的项目数。如果这小于参数的数量,则错误将报告原因。

总结:Scan将每个单词(由空格分隔的字符串)放入相应的参数中,将换行视为空格。 Scanln执行相同操作,但将换行符视为停止字符,而不是在此之后进一步解析。

如果您想阅读一行(最后为\n),请使用bufio.Reader及其ReadString方法:

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

答案 1 :(得分: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