How fmt.scan handles malformed numbers

Hello all,

My code asks for a number, then asks for another number. After that it prints each number in order, one over the other.

The odd thing is when I enter numbers with other chars in the number, strange things happen. I’ll show some examples below . My question is, why is this happening? And why is the odd behavior different on Windows and Linux for exactly the same code? These examples were ran on Linux; running this code on Windows show even more bizarre behavior. You’ll need to see the result on a Windows box for yourself.

// Ex.1 Normal run
$ go run numbers1.go
Enter number 1: 5
Enter number 2: 7
5
7

// Ex. 2 Malformed 2nd number - Here the 890 was entered on the second command line automatically
$ go run numbers1.go
Enter number 1: 123
Enter number 2: 567q890
123
567
[user@host.name.com code]$ 890
bash: 890: command not found…
Failed to search for file: Timeout was reached
[user@host.name.com code]$

// Ex. 3 Malformed 1st number - Here I only entered the first number, the second number appeared automatically.
[user@host.name.com code]$ go run numbers1.go
Enter number 1: 123q456
Enter number 2: 123
456
[user@host.name.com code]$

// Ex. 4 Malformed 1st number - Here I only entered the first number, the second number appeared automatically. After “Command not found…” I hit enter a couple of times but nothing happened so I did “CTRL-C”.
[user@host.name.com code]$
go run numbers1.go
Enter number 1: 123qwe456
Enter number 2: 123
0
[user@host.name.com code]$ e456
bash: e456: command not found…

^C
[user@host.name.com code]$

######### Not sure how to put code into code box.
package main

import (
“fmt”
)

func main() {

var num1 int64
var num2 int64

fmt.Print("Enter number 1: ")
fmt.Scan(&num1)

fmt.Print("Enter number 2: ")
fmt.Scan(&num2)

fmt.Println(num1)
fmt.Println(num2)

}
#################

You should never ignore errors. fmt.Scan has the signature

func Scan(a ...interface{}) (n int, err error)

Handle this error!

package main

import (
	"fmt"
	"log"
)

func main() {
	var num1 int64
	var num2 int64

	_, err := fmt.Print("Enter number 1: ")
	fmt.Scan(&num1)
	if err != nil {
		log.Panic(err)
	}

	fmt.Print("Enter number 2: ")
	_, err = fmt.Scan(&num2)
	if err != nil {
		log.Panic(err)
	}

	fmt.Println(num1)
	fmt.Println(num2)
}

If you run this code with invalid input, everythig is fine:

❯ go run forum.go
Enter number 1: 2
Enter number 2: 3
2
3
❯ go run forum.go
Enter number 1: a
Enter number 2: b
2020/08/21 07:51:08 expected integer
panic: expected integer

goroutine 1 [running]:
log.Panic(0xc00006cf40, 0x1, 0x1)
	/usr/local/Cellar/go/1.13.1/libexec/src/log/log.go:338 +0xac
main.main()
	/tmp/forum.go:22 +0x2a9
exit status 2
1 Like

Hi, thank you for your response.

For the first number, you catch the first error on the printf() line, like _, err := fmt.Print("Enter number 1: ")

But for the 2nd number, you catch the error on the fmt.Scan() line, _, err = fmt.Scan(&num2)

Why is this?
Also, do you know know why the odd behavior is happening, internally?

The assignment operator := must be used if there is a new identifier on the left. Since err is first declared here, := must be used. Later a new value is assigned to an existing identifer (err). For this, the operator = must be used.

Take a look at https://golang.org/ref/spec#Short_variable_declarations and https://golang.org/ref/spec#Assignments.

I have no idea why ignoring the errors causes the observed behavior.