Domanda
Sto cercando la Go equivalente di scanf (). Ho provato con seguente codice:
1 package main
2
3 import (
4 "scanner"
5 "os"
6 "fmt"
7 )
8
9 func main() {
10 var s scanner.Scanner
11 s.Init(os.Stdin)
12 s.Mode = scanner.ScanInts
13 tok := s.Scan()
14 for tok != scanner.EOF {
15 fmt.Printf("%d ", tok)
16 tok = s.Scan()
17 }
18 fmt.Println()
19 }
l'eseguo con il contributo di un testo con una linea di numeri interi. Ma è sempre uscita -3 -3 ...
E come per la scansione di una linea composta da una stringa e alcuni interi? Modifica della modalità ogni volta che incontra un nuovo tipo di dati?
La documentazione pacchetto:
scanner pacchetto
Uno scanner general-purpose per UTF-8 testo codificato.
Ma sembra che lo scanner non è per uso generale.
Codice Aggiornato:
func main() {
n := scanf()
fmt.Println(n)
fmt.Println(len(n))
}
func scanf() []int {
nums := new(vector.IntVector)
reader := bufio.NewReader(os.Stdin)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
i, _ := strconv.Atoi(f)
nums.Push(i)
}
str, err = reader.ReadString('\n')
}
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
}
Versione migliorata:
package main
import (
"bufio"
"os"
"io"
"fmt"
"strings"
"strconv"
"container/vector"
)
func main() {
n := fscanf(os.Stdin)
fmt.Println(len(n), n)
}
func fscanf(in io.Reader) []int {
var nums vector.IntVector
reader := bufio.NewReader(in)
str, err := reader.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = reader.ReadString('\n')
}
return nums
}
Soluzione
Il codice aggiornato è stato molto più facile da compilare senza i numeri di riga, ma mancava l'istruzioni package e import.
Guardando il codice, ho notato un paio di cose. Ecco la mia versione rivista del codice.
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"container/vector"
)
func main() {
n := scanf(os.Stdin)
fmt.Println()
fmt.Println(len(n), n)
}
func scanf(in io.Reader) []int {
var nums vector.IntVector
rd := bufio.NewReader(os.Stdin)
str, err := rd.ReadString('\n')
for err != os.EOF {
fields := strings.Fields(str)
for _, f := range fields {
if i, err := strconv.Atoi(f); err == nil {
nums.Push(i)
}
}
str, err = rd.ReadString('\n')
}
return nums
}
potrei voler utilizzare qualsiasi file di input per scanf()
, non solo Stdin
; scanf()
prende un io.Reader
come parametro.
Hai scritto: nums := new(vector.IntVector)
, dove type IntVector []int
. Questo assegna un nome nums
riferimento fetta intero ed inizializza a zero, allora la funzione new()
alloca un riferimento fetta intero ed inizializza a zero, e quindi assegna a nums
. Ho scritto:. var nums vector.IntVector
, che evita la ridondanza, semplicemente assegnando un nome di riferimento nums
fetta intera e l'inizializzazione a zero
Non hai controllare il valore err
per strconv.Atoi()
, il che significava un input non valido è stato convertito in un valore pari a zero; Ho saltare.
Per copiare dal vettore ad una nuova fetta e tornare la fetta, hai scritto:
r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
r[i] = nums.At(i)
}
return r
In primo luogo, ho semplicemente sostituito con un equivalente che, il metodo IntVector.Data()
: return nums.Data()
. Poi, ho approfittato del fatto che type IntVector []int
ed evitato l'assegnazione e la copia sostituendo che:. return nums
Altri suggerimenti
Anche se può essere utilizzato per altre cose, il pacchetto dello scanner è progettato per la scansione di Go testo del programma. Ints (-123), Chars ( 'c'), Strings ( "str"), ecc, sono Go lingua tipi di token.
package main
import (
"fmt"
"os"
"scanner"
"strconv"
)
func main() {
var s scanner.Scanner
s.Init(os.Stdin)
s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) }
s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
txt := s.TokenText()
fmt.Print("token:", tok, "text:", txt)
switch tok {
case scanner.Int:
si, err := strconv.Atoi64(txt)
if err == nil {
fmt.Print(" integer: ", si)
}
case scanner.String, scanner.RawString:
fmt.Print(" string: ", txt)
default:
if tok >= 0 {
fmt.Print(" unicode: ", "rune = ", tok)
} else {
fmt.Print(" ERROR")
}
}
fmt.Println()
}
}
In questo esempio si legge sempre in una linea alla volta e restituisce l'intera linea come una stringa. Se si vuole analizzare fuori valori specifici da esso si poteva.
package main
import (
"fmt"
"bufio"
"os"
"strings"
)
func main() {
value := Input("Please enter a value: ")
trimmed := strings.TrimSpace(value)
fmt.Printf("Hello %s!\n", trimmed)
}
func Input(str string) string {
print(str)
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
return input
}
In un commento ad una delle mie risposte, lei ha detto:
Dal Specification Language: "Quando memoria è allocata per memorizzare un valore, tramite una dichiarazione o fanno () o nuova () chiamata, e non esplicita inizializzazione è previsto, la memoria è dato un'inizializzazione default". Allora qual è il punto di new ()?
Se corriamo:
package main
import ("fmt")
func main() {
var i int
var j *int
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j)
j = new(int)
fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j)
}
Il var i int
dichiarazione alloca memoria per memorizzare un valore intero e inizializza il valore zero. Il var j *int
dichiarazione alloca memoria per memorizzare un puntatore a un valore intero e inizializza il puntatore a zero (un puntatore nullo); nessuna memoria è allocata per memorizzare un valore intero. Vediamo l'output del programma simile a:
i (a value) = 0 ; j (a pointer) = <nil>
La funzione new
built-in prende un tipo T
e restituisce un valore di tipo *T
. La memoria viene inizializzata a valori zero. Il j = new(int)
dichiarazione alloca memoria per memorizzare un valore intero e inizializza il valore zero, allora memorizza un puntatore a questo valore intero j. Vediamo l'output del programma simile a:
i (a value) = 0 ; j (a pointer) = 0x7fcf913a90f0 ; *j (a value) = 0
L'ultima versione di Go (2010-05-27) ha aggiunto due funzioni al pacchetto fmt
: Scan()
e Scanln()
. Non prendono qualsiasi stringa modello. come in C, ma controlla il tipo di argomenti, invece.
package main
import (
"fmt"
"os"
"container/vector"
)
func main() {
numbers := new(vector.IntVector)
var number int
n, err := fmt.Scan(os.Stdin, &number)
for n == 1 && err == nil {
numbers.Push(number)
n, err = fmt.Scan(os.Stdin, &number)
}
fmt.Printf("%v\n", numbers.Data())
}