How to check if Scanln throws an error in Golang - go

I am new to Go. I've been searching for answers and I know there really is one I just haven't found it.
To better explain my question, here is my code:
func main() {
...
inputs := new(Inputs)
fmt.Println("Input two numbers: ")
fmt.Scanln(&inputs.A)
fmt.Scanln(&inputs.B)
fmt.Println("Sum is:", inputs.A + inputs.B)
}
And here is my struct:
type Inputs struct {
A, B int
}
If I will input '123' for Input A and another '123' for Input B, I will have an output of "Sum is: 246". But if I will mistakenly input '123j' , it will no longer work since A and B accept int(s) only.
Now, how to catch the panic from fmt.Scanln or is there a way? Thanks in advance.

Scanln returns values ... don't ignore them.
You're ignoring two important return values. The count of the scan and an error .. if there was one.
n, err := fmt.Scanln(&inputs.A)
...will give you what you need to check. err will tell you that a newline was expected and wasn't found .. because you've tried to store the value in an int .. and it errors when the last character in the available value isn't a newline.

Related

How can I scan a rune?

So far, I haven't been able to print a rune by scanning it with fmt.Scan and printing it with fmt.Print. This is the vary basic code I'm working on:
package main
import "fmt"
func main() {
var c rune
fmt.Scan(&c)
fmt.Printf("%c", c)
}
But it doesn't work, in fact, Printf doesn't produce any output. Instead, by manually assigning a char to my variable c (like var c rune = 'a', without using fmt.Scan), I'm able to print the wanted rune. How can I scan a rune?
As we know Scan return n and err so please check for error under Scan statement as follows
n, err := fmt.Scan(&c)
if err != nil {
fmt.Println(err)
}
It will clearly show you the error and why it was ignored.
Other than the above, please try it locally on your own laptop instead of the playground because on the playground it most of the time gives an EOF error as most of them do not support reading from the terminal.
I hope the above helps you in debugging the issue.
Other Reference:
Scanf ignores if not provided \n

In Go, how to verify that the data type of an input from the user matches the data type of the code?

I am new to Go.
Currently, I am creating a menu in Go and I want to verify that the data type of the input from the user matches the data type of the variable defined in the code. Part of my code looks like this so far:
package main
import (
"fmt"
"reflect"
)
var option int // The variable is declared outside of the main().
func general_menu() {
fmt.Println(".......................General Menu..................................")
fmt.Println()
fmt.Println("Calculator..........................................................1")
fmt.Println("Linear algebra package..............................................2")
fmt.Println("Language change.....................................................9")
fmt.Println("Exit...............................................................10")
fmt.Println()
fmt.Println("Choose an option from the menu.")
fmt.Println()
fmt.Scan(&option)
fmt.Println()
if (option != 1 && option != 2 && option != 9 && option != 10)||reflect.TypeOf(option)!=int{
fmt.Println("Wrong option input. Please, try again.")
fmt.Println()
general_menu()
}
}
I know that this doens't work this way, and I know that "int" can not be used as part of an "if" condirion.
I would kindly appreciate any suggestions on the proper way to solve this problem.
Thanks.
Edit: I have added more of my code as kindly suggested by the contributors.
Edit: Based on the answer provided, I have tried to implement a function, but the syntax is still not correct:
func check_integers_are_not_string(x int) bool {
change := strconv.Itoa(x)
if change != nil {
return true
} else {
return false
}
} // This function returns a true boolean value if conversion from int to string was possible, meaning that the entered value is a string.
Just read the documentation of Scan - https://pkg.go.dev/fmt#Scan
It returns the number of successfully read arguments and an error. The input is mapped in your case to a variable of type int, so if a user inputs a string it will return 0 and an error. Otherwise it will return 1 and the error should be nil. You can check for that.
n, err := fmt.Scan(&option)
if n != 1 || err != nil {
// print error and go back
}
One common way to do it is to try to make the conversion and see if it succeeds.
optionInt, err := strconv.Atoi(option) // Assuming option is of type string
if err != nil {
log.Printf("String '%s' cannot be converted to type int: %v", option, err)
os.Exit(1)
}
log.Printf(`optionInt is %d.`, optionInt)
This is a good approach if you are only interested in conversion to one type. Otherwise things can quickly get more involved, utilizing constructs such as lexers and parsers, but that would warrant more information on what you are trying to accomplish.

reading same input with bufio and scanf has different results

I was trying to write a simple program that reads some answers from the terminal from the user to some questions.For instance the queries are:
5+5
1+2
8+3
and the user should give the answer.My problem it that when I user bufio.ReadString and the compare the input with the real answer it doesn't work properly,how ever when I use scanf everything is fine.here is my code:
//scanner := bufio.NewReader(os.Stdin)
var correctAnswers int8 = 0
for _, pro := range problems {
fmt.Println(pro.question)
//answer,_ := scanner.ReadString('\n')
var idk string
fmt.Scanf("%s\n", &idk)
//print(answer)
println(pro.answer)
if idk == pro.answer {
fmt.Println("Correct :)")
correctAnswers++
} else {
fmt.Println("Sorry!")
}
}
fmt.Printf("You answered %d out of %d problems correctly \n", correctAnswers, len(problems))
as you can see I commented out bufio. The intersting thing is that when I print the answer that the user gave me it bufio.ReadString correctly got the input from terminal but in the if clause it doesn't work!
bufio.Reader.ReadString:
ReadString reads until the first occurrence of delim in the input, returning a string containing the data up to and including the delimiter.
The value returned from ReadString includes the \n on the end.

Print dereferenced structs from slice of pointers to structs

In Golang, is there an easy way to print for debugging the dereferenced pointers given a slice of pointers to structs?
If you don't want to use unsafe and an external package.. you can range over it yourself:
for _, p := range people {
fmt.Printf("%+v\n", p)
}
Output:
&{name:Simon age:25}
&{name:Bob age:31}
Working sample: http://play.golang.org/p/aVw0rhQNuk
Maybe it's a late answer, but I've just come across the same problem and wanna save my choice here for anyone needed.
I added a String() function to my item type. For example:
type SliceItem struct {
ID int32
Name string
}
func (i *SliceItem) String() string {
return fmt.Sprintf("id = %d, name = %s\n", i.ID, i.Name)
}
As a result, whenever I wanna print this item, I got friendly "id = xx, name = xxx" string, instead of unreadable pointer addresses.
If you want to print individual elements, try it with the index and asterix for dereferencing:
fmt.Println(*pointer_strcut_slice[0])
fmt.Println(*pointer_strcut_slice[1])

How to ignore fields with sscanf (%* is rejected)

I wish to ignore a particular field whilst processing a string with sscanf.
Man page for sscanf says
An optional '*' assignment-suppression character: scanf() reads input as directed by the conversion specification, but discards the input. No corresponding pointer argument is required, and this specification is not included in the count of successful assignments returned by scanf().
Attempting to use this in Golang, to ignore the 3rd field:
if c, err := fmt.Sscanf(str, " %s %d %*d %d ", &iface.Name, &iface.BTx, &iface.BytesRx); err != nil || c != 3 {
compiles OK, but at runtime err is set to:
bad verb %* for integer
Golang doco doesn't specifically mention the %* conversion specification, but it does say,
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
It doesn't indicate that %* is not implemented, so... Am I doing it wrong? Or has it just been quietly omitted? ...but then, why does it compile?
To the best of my knowledge there is no such verb (as the format specifiers are called in the fmt package) for this task. What you can do however, is specifying some verb and ignoring its value. This is not particularly memory friendly, though. Ideally this would work:
fmt.Scan(&a, _, &b)
Sadly, it doesn't. So your next best option would be to declare the variables and ignore the one
you don't want:
var a,b,c int
fmt.Scanf("%d %v %d", &a, &b, &c)
fmt.Println(a,c)
%v would read a space separated token. Depending on what you're scanning on, you may fast forward the
stream to the position you need to scan on. See this answer
for details on seeking in buffers. If you're using stdio or you don't know which length your input may
have, you seem to be out of luck here.
It doesn't indicate that %* is not implemented, so... Am I doing it
wrong? Or has it just been quietly omitted? ...but then, why does it
compile?
It compiles because for the compiler a format string is just a string like any other. The content of that string is evaluated at run time by functions of the fmt package. Some C compilers may check format strings
for correctness, but this is a feature, not the norm. With go, the go vet command will try to warn you about format string errors with mismatched arguments.
Edit:
For the special case of needing to parse a row of integers and just caring for some of them, you
can use fmt.Scan in combination with a slice of integers. The following example reads 3 integers
from stdin and stores them in the slice named vals:
ints := make([]interface{}, 3)
vals := make([]int, len(ints))
for i, _ := range ints {
ints[i] = interface{}(&vals[i])
}
fmt.Scan(ints...)
fmt.Println(vals)
This is probably shorter than the conventional split/trim/strconv chain. It makes a slice of pointers
which each points to a value in vals. fmt.Scan then fills these pointers. With this you can even
ignore most of the values by assigning the same pointer over and over for the values you don't want:
ignored := 0
for i, _ := range ints {
if(i == 0 || i == 2) {
ints[i] = interface{}(&vals[i])
} else {
ints[i] = interface{}(&ignored)
}
}
The example above would assign the address of ignore to all values except the first and the second, thus
effectively ignoring them by overwriting.

Resources