Reading User Inputs in Go¶
Table of Contents¶
- Managing Modules
- Command Line Arguments & Environment Variables
- Pointers and Getting User Input
- Getting User Input
- Switch vs. If/Else
Managing Modules¶
Can have multiple modules within a single Git repository.
Create a new module for each project. You can keep them all in one repository,
creating a monorepo with all your projects.
go mod init github.com/kolkhis/learn-go/new-go-project
go run- run the codego install- build a binary in the$GOBINpathgo build- builds a binary in the current directory``go install -o ./testbin- will output to the specified path/name
Command Line Arguments & Environment Variables¶
In go, the os module can be used to get command line arguments.
Use os.Args to get the CLI arguments.
~/Repos/github.com/kolkhis/learn-go/hi
package main
import (
"fmt"
"os"
)
func main() {
// os.Getenv()
// First in Args is always the name of the program
name := "Friend"
if n := os.Getenv("USER"); len(n) > 0 {
name = n
}
if len(os.Args) > 1 {
name = os.Args[1]
}
fmt.Println("Hi, " + name + ".")
}
The if check for n := os.Getenv("USER"); len(n) > 0 checks if the length of n is greater than zero.
This method is faster than checking for an empty string (n == "")
First item in Args is always the name of the program,
Pointers and Getting User Input¶
See pointers
Pointers¶
Similar to C, but not as complicated as pointers in C.
fmt.Println("What is your name? ${white}")
var name string
fmt.Scanln(&name) // This will be a pointer dereference
// This is passing-by-reference.
fmt.Scanln reads from standard input. Stops reading at newline or end of file.
Strings are usually not passed by reference, but other types are.
In this case, strings and integers must be passed by reference.
Since fmt.Scanln needs to modify the value of the name variable, the only way
to do this is to pass a Pointer to the function - its memory address (&name).
&namepasses the memory address of thenamevariable (a pointer) tofmt.Scanln.-
fmt.Scanlndereferences the pointer (accesses the value stored at the memory address) and modifies the actualnamevariable.
Why a pointer is needed here: -
fmt.Scanlnneeds to assign the user input to thenamevariab.e - Without passing its address,
fmt.Scanlnwould only work with a copy ofnameand wouldn't be able to modify the original variable.
So, if you need to pass a variable to a function in order to modify its value, use a pointer.
Example: Using a pointer to modify a variable directly¶
package main
import ("fmt")
func ChangeAge(age *int) newage int {
*age = newage
}
func main() {
var age int = 30
fmt.Println("Your age:", age)
ChangeAge(&age, 33)
fmt.Printf("New age: %v\n", age)
}
If you called ChangeAge without referencing &age, it would only pass the value
of age (30).
Getting User Input¶
fmt.Scanln might be okay for one-word/one-time inputs.
// Make a scanner (it's buffered), pass a reference to stdin
scanner := bufio.NewScanner(os.Stdin) // This is supported on all platforms.
fmt.Println("Enter a line of text: ")
// Does a scan until the first EOL (\n or \r\n)
scanner.Scan()
// Truncates the EOL
text := scanner.Text()
fmt.Println("You entered:", text)
But reading input is generally done with a bufio.NewScanner object, which takes
either a file or os.Stdin as an argument.
scanner := bufio.NewScanner(os.Stdin) // Can replace `os.Stdin` with any input (files)
scanner.Scan()
// Truncates the EOL
text := scanner.Text()
ScanLines is the default. Strips trailing and EOL marker. EOL marker is optional carriage return
followed by one mandatory newline. Automatically truncates. Don't use ReadLines.
Always use bufio.NewScanner(os.Stdin)
Switch vs. If/Else¶
It's generally considered better form to use switch cases instead of if/else chains when you have multiple conditions.
Switches are more versatile too in that you can use a "Type Switch" to check for types if you need to do that.
BAD GO CODE (if/else if chains):¶
BAD GO: else if statements.
if name == "Robin" {
fmt.Println("What is your capital of Assyria?")
} else if name == "Lancelot" {
fmt.Println("What is your favorite colour?")
} else if name == "Arthur" {
fmt.Println("What is the air speed velocity of an unladen swallow?")
fmt.Println("How do you know so much about swallows?")
fmt.Println("Well, as a King you have to know these things, you know.")
}
GOOD GO CODE (swich case):¶
In Go, switch statements are the preferred idiomatic way for conditionals.
switch strings.ToLower(name) {
// The {surrounding braces} for `case` statements are options
case "robin": { fmt.Println("What is your capital of Assyria?") }
fallthrough
case "lancelot": { fmt.Println("What is your favorite colour?") }
case "arthur": {
fmt.Println("What is the air speed velocity of an unladen swallow?")
fmt.Println("How do you know so much about swallows?")
fmt.Println("Well, as a King you have to know these things, you know.")
}
case, in C, it's required to use break;.
The Go equivalent in the fallthrough keyword.
Type Switch¶
Also see type switches with interfaces