2013-07-01 23 views
5

Sto lavorando attraverso il libro Go di Caleb Doxsey e ho due domande su fmt.Scanfhttp://www.golang-book.com/4Perché fmt.Scanf in Go non aspetta l'input dell'utente?

Mi chiedo il motivo per cui il programma non si ferma dopo il secondo Scanf e attendere l'input dell'utente? E come posso verificare se l'utente ha inserito un numero intero e/o non ha lasciato nulla?

package main 

import (
"fmt" 
//"math" 
) 


// compute square roots by using Newton's method 

func main() { 

var x float64   //number to take square root 
var y float64   //this is the guess 
var q float64   //this is the quotient 
var a float64   //this is the average 


// how do check if the user entered a number 
fmt.Print("Enter a number to take its square root: ") 
var inputSquare float64 
fmt.Scanf("%f", &inputSquare) 

// why doesn't program stop after 
// the Print statement and wait 
// for user input? 
fmt.Print("Enter first guess ") 
var inputGuess float64 
fmt.Scanf("%f", &inputGuess) 

//x = 2 
x = inputSquare 
y = inputGuess 

for i := 0; i < 10; i++ { //set up the for loop for iterations 
    q = x/y     //compute the quotient; x and y are given 
    a = (q + y)/x   //compute the average  
    y = a     //set the guess to the average    
}       //for the next loop 


fmt.Println("y --> ", y) 
//fmt.Println("Sqrt(2)", math.Sqrt(2)) 
} 
+1

Funziona correttamente per me. Ho intenzione di indovinare che si tratta di un problema di fine linea. Se stai lavorando su Windows, i finali di linea sono convenzionalmente indicati con '\ r \ n', mentre su Mac OS X e Linux (dove ho provato questo), è solo '\ n'. La mia ipotesi è che forse Go sta leggendo il '\ r', trattandolo come una linea che termina e lasciando il \ n 'sul flusso. Quindi quando richiama fmt.Scanf di nuovo, c'è già qualcosa nel buffer e non c'è bisogno di bloccarlo. Questa è solo un'ipotesi. – deong

+0

ok. Qualche suggerimento su come risolverlo? Questo è ciò che ottengo in esecuzione nella riga di comando di Windows: c: \ Go \ src \ play \ exercise> go run loop_exercise.go Inserire un numero per ottenere la radice quadrata: 2 Immettere la prima ipotesi y -> + Inf – Zeynel

+1

Cosa succede se si legge esplicitamente un carattere di nuova riga con la chiamata Scanf? Come "' fmt.Scanf ("% f \ n", & inputGuess) '"? In alternativa, puoi svuotare lo stdin dopo ogni lettura. Non so andare abbastanza bene da sapere dove dirti di cercare una funzione Flush. – deong

risposta

9

E 'Issue 5391: fmt: Scanf respinge \r\n alla fine della riga su Windows.

Come soluzione e per controllare input valido, scrivere,

var inputSquare float64 
n, err := fmt.Scanf("%f\n", &inputSquare) 
if err != nil || n != 1 { 
    // handle invalid input 
    fmt.Println(n, err) 
} 

e

var inputGuess float64 
n, err = fmt.Scanf("%f\n", &inputGuess) 
if err != nil || n != 1 { 
    // handle invalid input 
    fmt.Println(n, err) 
} 

La soluzione è la nuova riga nelle stringhe di formato "%f\n".

pacchetto fmt

func Scanf

func Scanf(format string, a ...interface{}) (n int, err error) 

Scanf scansioni testo letto dallo standard input, memorizzare successivi valori separati da spazio in argomenti successivi come determinato dal formato . Restituisce il numero di elementi sottoposti a scansione.

Ecco un programma di lavoro completo:

package main 

import (
    "fmt" 
) 

// compute square roots by using Newton's method 
func main() { 
    var x float64 //number to take square root 
    var y float64 //this is the guess 
    var q float64 //this is the quotient 
    var a float64 //this is the average 

    fmt.Print("Enter a number to take its square root: ") 
    var inputSquare float64 
    n, err := fmt.Scanf("%f\n", &inputSquare) 
    if err != nil || n != 1 { 
     // handle invalid input 
     fmt.Println(n, err) 
     return 
    } 

    fmt.Print("Enter first guess ") 
    var inputGuess float64 
    n, err = fmt.Scanf("%f\n", &inputGuess) 
    if err != nil || n != 1 { 
     // handle invalid input 
     fmt.Println(n, err) 
     return 
    } 

    x = inputSquare 
    y = inputGuess 
    for i := 0; i < 10; i++ { 
     q = x/y  // compute the quotient; x and y are given 
     a = (q + y)/x // compute the average 
     y = a   // set the guess to the average 
    } 
    fmt.Printf("sqrt(%g) = %g\n", x, y) 
} 

uscita:

Enter a number to take its square root: 2.0 
Enter first guess 1.0 
sqrt(2) = 1.414213562373095 

ho usato Go 1.1.1 su Windows 7:

C:\>go version 
go version go1.1.1 windows/amd64 
+0

Grazie. 'Fmt.Scanf()' restituisce un errore? Presumo, 'n' è l'input e' err' è il messaggio di errore possibile in 'n, err: = fmt.Scanf ("% f \ n ", & inputSquare)' È corretto? – Zeynel

+1

Vedere la mia risposta modificata. 'n' è il numero di elementi scansionati con successo e' err' segnala eventuali errori incontrati durante la scansione. Pertanto, se c'è stato un errore o il numero di elementi scansionati non è quello che ti aspetti ('err! = Nil || n! = 1'), fai qualcosa per gestire l'errore.Tuttavia, se tutto va bene ('err == nil && n == 1'), l'input valido, come numero a virgola mobile (' float64'), può essere letto da '* inputSquare'. Nel tuo codice, hai scartato 'n' e' err', ecco perché non hai notato errori. – peterSO

+0

Devo fare qualcosa di sbagliato. Se si esegue il programma con la gestione degli errori parte 'n, err: = fmt.Scanf ("F \ n", e inputSquare) \t \t \t \t // ritirare l'errore \t se err = nil ||! n! = 1 { \t \t fmt.Println (n, err) 'I get" 0 l'input non corrisponde al formato "(inserisco, ad esempio, 2.0 per inputSquare) Se commento l'errore gestendolo tutto funziona correttamente! Che cosa sto facendo di sbagliato? – Zeynel