I'm trying to convert a string returned from flag.Arg(n) to an int. What is the idiomatic way to do this in Go?
6 Answers
For example strconv.Atoi.
Code:
package main
import (
"fmt"
"strconv"
)
func main() {
s := "123"
// string to int
i, err := strconv.Atoi(s)
if err != nil {
// ... handle error
panic(err)
}
fmt.Println(s, i)
}
6 Comments
strconv can be interpreted as String Convert likewise, is there any meaning (extension) for Atoi to make it easier to remember.atoi() library function.strconv.ParseInt() which takes a string, a base, and integer size. Atoi(s) is equivalent to ParseInt(s, 10, 0) (which is actually mentioned right on the page this answer links to). @Roger Glover: In addition to @MarioVilas's comment, the only supported digits are in fact ASCII. I don't think it's reasonable to expect the function to convert all of the various non-ASCII digit characters like circled digits, superscript/subscript digits, etc.Converting Simple strings
The easiest way is to use the strconv.Atoi() function.
Note that there are many other ways. For example fmt.Sscan() and strconv.ParseInt() which give greater flexibility as you can specify the base and bitsize for example. Also as noted in the documentation of strconv.Atoi():
Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
Here's an example using the mentioned functions (try it on the Go Playground):
flag.Parse()
s := flag.Arg(0)
if i, err := strconv.Atoi(s); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
var i int
if _, err := fmt.Sscan(s, &i); err == nil {
fmt.Printf("i=%d, type: %T\n", i, i)
}
Output (if called with argument "123"):
i=123, type: int
i=123, type: int64
i=123, type: int
Parsing Custom strings
There is also a handy fmt.Sscanf() which gives even greater flexibility as with the format string you can specify the number format (like width, base etc.) along with additional extra characters in the input string.
This is great for parsing custom strings holding a number. For example if your input is provided in a form of "id:00123" where you have a prefix "id:" and the number is fixed 5 digits, padded with zeros if shorter, this is very easily parsable like this:
s := "id:00123"
var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
fmt.Println(i) // Outputs 123
}
4 Comments
ParseInt specify?strconv.ParseInt() link and you'll see immediately: ParseInt(s string, base int, bitSize int). So it's the base: "ParseInt interprets a string s in the given base (2 to 36) "int is required and strconv.ParseInt() is used, manual type conversion is needed (from int64 to int).Here are three ways to parse strings into integers, from fastest runtime to slowest:
strconv.ParseInt(...)fasteststrconv.Atoi(...)still very fastfmt.Sscanf(...)not terribly fast but most flexible
Here's a benchmark that shows usage and example timing for each function:
package main
import "fmt"
import "strconv"
import "testing"
var num = 123456
var numstr = "123456"
func BenchmarkStrconvParseInt(b *testing.B) {
num64 := int64(num)
for i := 0; i < b.N; i++ {
x, err := strconv.ParseInt(numstr, 10, 64)
if x != num64 || err != nil {
b.Error(err)
}
}
}
func BenchmarkAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
x, err := strconv.Atoi(numstr)
if x != num || err != nil {
b.Error(err)
}
}
}
func BenchmarkFmtSscan(b *testing.B) {
for i := 0; i < b.N; i++ {
var x int
n, err := fmt.Sscanf(numstr, "%d", &x)
if n != 1 || x != num || err != nil {
b.Error(err)
}
}
}
You can run it by saving as atoi_test.go and running go test -bench=. atoi_test.go.
goos: darwin
goarch: amd64
BenchmarkStrconvParseInt-8 100000000 17.1 ns/op
BenchmarkAtoi-8 100000000 19.4 ns/op
BenchmarkFmtSscan-8 2000000 693 ns/op
PASS
ok command-line-arguments 5.797s
2 Comments
Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. pkg.go.dev/strconv#AtoiTry this
import ("strconv")
value := "123"
number,err := strconv.ParseUint(value, 10, 32)
finalIntNum := int(number) //Convert uint64 To int
1 Comment
uint32 range but not in the int range on platforms where int is 32 bits. Example value: "4234567890" is converted to -60399406. Go Playground (64 bits)If you control the input data, you can use the mini version
package main
import (
"testing"
"strconv"
)
func Atoi (s string) int {
var (
n uint64
i int
v byte
)
for ; i < len(s); i++ {
d := s[i]
if '0' <= d && d <= '9' {
v = d - '0'
} else if 'a' <= d && d <= 'z' {
v = d - 'a' + 10
} else if 'A' <= d && d <= 'Z' {
v = d - 'A' + 10
} else {
n = 0; break
}
n *= uint64(10)
n += uint64(v)
}
return int(n)
}
func BenchmarkAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
in := Atoi("9999")
_ = in
}
}
func BenchmarkStrconvAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
in, _ := strconv.Atoi("9999")
_ = in
}
}
the fastest option (write your check if necessary). Result :
Path>go test -bench=. atoi_test.go
goos: windows
goarch: amd64
BenchmarkAtoi-2 100000000 14.6 ns/op
BenchmarkStrconvAtoi-2 30000000 51.2 ns/op
PASS
ok path 3.293s
6 Comments
If you need to parse strings really fast, you can use faiNumber package. faiNumber is the fastest golang string parser library. All of faiNumber's function was benchmark to run way faster than the strconv package. faiNumber supports parsing strings of decimal, binary, octal, hex to an int32, uint32, int64, uint64 data type. faiNumber also supports converting an int32, uint32, int64, or uint64 values to a decimal string, a binary string, an octal string, or a hex string.
You can download faiNumber from https://github.com/kevinhng86/faiNumber-Go. After download, put the faiNumber folder in your module path and import using <module_path>/faiNumber. Or you can install the faiNumber package using "go install github.com/kevinhng86/faiNumber-Go/faiNumber@latest" then using "go get github.com/kevinhng86/faiNumber-Go/faiNumber" in your module directory. If you choose to install faiNumber using go install, then you can keep the same import path
The documentation for faiNumber can be found here https://lib.fai.host/go/github.com/kevinhng86/faiNumber-Go/faiNumber/ .
I wrote faiNumber and hope that one day it will make it to the standard library.
Below is the code example for using faiNumber to parse a string of decimal to either an int32, a uint32, an int64, or a uint64 value.
package main
import "fmt"
import "github.com/kevinhng86/faiNumber-Go/faiNumber"
func main() {
var nInt32 int32
var nUint32 uint32
var nInt64 int64
var nUint64 uint64
var err error
str := "123"
// Decimal string to int32
nInt32, err = faiNumber.DecToInt32(str)
if err != nil {
// Error handling
fmt.Println(err)
} else {
// No error path
fmt.Printf("String: \"%s\", int32: %d\n\n", str, nInt32)
}
// Decimal string to uint32, sign prefix is not permitted
nUint32, err = faiNumber.DecToUInt32(str)
if err != nil {
// Error handling
fmt.Printf("FromFunction: %s, Input: \"%s\", Error Code: %d, Error Message: %s.\n\n",
err.(*faiNumber.FNError).FromFunction, err.(*faiNumber.FNError).Input,
err.(*faiNumber.FNError).Code, err.(*faiNumber.FNError).Message)
} else {
// No error path
fmt.Printf("String: \"%s\", uint32: %d\n\n", str, nUint32)
}
// Decimal string to int64
nInt64, err = faiNumber.DecToInt64(str)
if err != nil {
// Error handling
fmt.Println(err)
} else {
// No error path
fmt.Printf("String: \"%s\", int64: %d\n\n", str, nInt64)
}
// Decimal string to uint64, sign prefix is not permitted
nUint64, err = faiNumber.DecToUInt64(str)
if err != nil {
// Error handling
fmt.Println(err)
} else {
// No error path
fmt.Printf("String: \"%s\", uint64: %d\n\n", str, nUint64)
}
}
strconv.Itoa(i)(int to ASCII) to set an int to a string. See stackoverflow.com/a/62737936/12817546.strconv.Atoi(s)(ASCII to int) to set a string to an int. See stackoverflow.com/a/62740786/12817546.