如何使 fmt.Scanln() 读取整数切片

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

How to make fmt.Scanln() read into a slice of integers

问题

我有一行包含3个数字的代码,我想用fmt.Scanln()从stdin中读取,但是这段代码不起作用:

X := make([]int, 3)
fmt.Scanln(X...)
fmt.Printf("%v\n", X)

我得到了这个错误信息:

cannot use X (type []int) as type []interface {} in function argument

我不明白。

英文:

I have a line containing 3 numbers that I want to read from stdin with fmt.Scanln() but this code won't work:

X := make([]int, 3)
fmt.Scanln(X...)
fmt.Printf("%v\n", X)

I get this error message:

cannot use X (type []int) as type []interface {} in function argument

I don't get it.

答案1

得分: 13

习惯用法的Go代码如下:

func read(n int) ([]int, error) {
  in := make([]int, n)
  for i := range in {
	_, err := fmt.Scan(&in[i])
    if err != nil {
       return in[:i], err
    }
  }
  return in, nil
}

interface{} 意味着什么都没有。如果不必要,请不要使用它。

英文:

Idiomatic Go would be:

func read(n int) ([]int, error) {
  in := make([]int, n)
  for i := range in {
	_, err := fmt.Scan(&in[i])
    if err != nil {
       return in[:i], err
    }
  }
  return in, nil
}

interface{} means nothing. Please don't use it if you don't have to.

答案2

得分: 10

例如,

package main

import "fmt"

func intScanln(n int) ([]int, error) {
    x := make([]int, n)
    y := make([]interface{}, len(x))
    for i := range x {
        y[i] = &x[i]
    }
    n, err := fmt.Scanln(y...)
    x = x[:n]
    return x, err
}

func main() {
    x, err := intScanln(3)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%v\n", x)
}

输入:

1 2 3

输出:

[1 2 3]
英文:

For example,

package main

import "fmt"

func intScanln(n int) ([]int, error) {
	x := make([]int, n)
	y := make([]interface{}, len(x))
	for i := range x {
		y[i] = &x[i]
	}
	n, err := fmt.Scanln(y...)
	x = x[:n]
	return x, err
}

func main() {
	x, err := intScanln(3)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%v\n", x)
}

Input:

1 2 3

Output:

[1 2 3]

答案3

得分: 1

我认为正确的版本应该是

X := make([]int, 3)
fmt.Scanln(&X[0], &X[1], &X[2])
fmt.Printf("%v\n", X)
英文:

I think the the correct version should be

X := make([]int, 3)
fmt.Scanln(&X[0], &X[1], &X[2])
fmt.Printf("%v\n", X)

答案4

得分: 1

这个错误消息发生是因为没有合理的方法将[]int转换为[]interface{}。注意,这是针对切片的。所以你使用的语法是正确的,但是fmt.Scanln期望的是[]interface{}。这对于fmt包之外的包有影响。

给出这个错误的原因是因为Go语言允许你控制内存布局,所以目前没有合理的方法来进行切片转换。这意味着在将切片传递给期望特定类型切片的函数之前,你需要手动进行转换。例如:

package main

import (
	"fmt"
)

func main() {
	x := make([]int, 3)
	y := make([]interface{}, 3)
	y[0] = x[0]
	y[1] = x[1]
	y[2] = x[2]

	fmt.Println(y...)
}

或者更通用一些的方法:

x := make([]int, 3)
y := make([]interface{}, len(x))
for i, v := range x {
	y[i] = v
}

fmt.Println(y...)

关于你的具体问题,请参考以下代码:

x := make([]*int, 3)
for i := range x {
	x[i] = new(int)
}

y := make([]interface{}, 3)

for i, v := range x {
	y[i] = v
}

if _, err := fmt.Scanln(y...); err != nil {
	fmt.Println("Scanln err: ", err)
}

for _, v := range y {
	val := v.(*int)
	fmt.Println(*val)
}
英文:

This error message occurs b/c there's no reasonable way to convert []int to []interface{}. Note, this is in reference to a slice. So the syntax your using is correct, but fmt.Scanln expects []interface{}. This has implications outside of pkg fmt.

The reason I've seen given for this is due to Go giving you control over memory layout so it currently has no reasonable way to do the slice conversion. This means you'll need to do the conversion manually before passing it to a function expecting the slice of a given type. For example:

package main

import (
	"fmt"
)

func main() {
	x := make([]int, 3)
	y := make([]interface{}, 3)
	y[0] = x[0]
	y[1] = x[1]
	y[2] = x[2]

	fmt.Println(y...)
}

Or something a little more general:

	x := make([]int, 3)
	y := make([]interface{}, len(x))
	for i, v := range x {
		y[i] = v
	}

	fmt.Println(y...)

Regarding your specific issue, see the following:

	x := make([]*int, 3)
	for i := range x {
		x[i] = new(int)
	}

	y := make([]interface{}, 3)
	
	for i, v := range x {
		y[i] = v
	}
	
	if _, err := fmt.Scanln(y...); err != nil {
		fmt.Println("Scanln err: ", err)
	}

	for _, v := range y {
		val := v.(*int)
		fmt.Println(*val)
	}

答案5

得分: 0

package main

import (
"bytes"
"fmt"
)

type slice struct {
tok []int
}

func (s *slice) 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)
}
}
b := bytes.NewReader(tok)
for {
var d int
_, err := fmt.Fscan(b, &d)
if err != nil { break }
s.tok = append(s.tok, d)
}
return nil
}

func main() {
var s slice
fmt.Scan(&s)
fmt.Println(s.tok)
}

英文:

I saw in a comment you said the lines can have different lengths. In that case
you can implement your own fmt.Scanner:

package main

import (
   "bytes"
   "fmt"
)

type slice struct {
   tok []int
}

func (s *slice) 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)
      }
   }
   b := bytes.NewReader(tok)
   for {
      var d int
      _, err := fmt.Fscan(b, &d)
      if err != nil { break }
      s.tok = append(s.tok, d)
   }
   return nil
}

func main() {
   var s slice
   fmt.Scan(&s)
   fmt.Println(s.tok)
}

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

huangapple
  • 本文由 发表于 2013年3月14日 23:30:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/15413469.html
匿名

发表评论

匿名网友

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

确定