Golang: parse a signed int - go

I have some code that needs to be able to parse a string containing a 64-bit value into an int64. For example, ff11223344556677 is valid, but a downstream system wants that in an int64.
strconv.ParseInt("ff11223344556677", 16, 64) gives a range error - it only likes to parse positive integers. Is there a way to go about putting this value into an int64 even though it is going to be negative?

For example,
package main
import (
"fmt"
"strconv"
)
func main() {
u, err := strconv.ParseUint("ff11223344556677", 16, 64)
fmt.Printf("%x %v\n", u, err)
i := int64(u)
fmt.Println(i)
}
Output:
ff11223344556677 <nil>
-67234915848722825

Related

Convert binary value as string to uint32 in Golang

Hello i am trying to convert 00000000000000000000000000001011 to uint32 in golang using
var v = "00000000000000000000000000001011"
fmt.Printf("%T\n", v)
c := []byte(v)
u := binary.LittleEndian.Uint32(c)
However it is not working.
You can't use encoding/binary for this, as that is to serialize and deserialize the (memory) bytes of different values (e.g. numbers). What you have is the base 2 string representation of the number.
To get its integer value you have to parse it. For that, use strconv.ParseUint():
s := "00000000000000000000000000001011"
u, err := strconv.ParseUint(s, 2, 32)
if err != nil {
panic(err)
}
fmt.Println(u)
This outputs (try it on the Go Playground):
11
Note that strconv.ParseUint() returns a value of type uint64, so if you need uint32, you have to manually convert it, e.g.:
u32 := uint32(u)
There are more options for parsing numbers from strings, for an overview, check Convert string to integer type in Go?
For example,
package main
import (
"fmt"
"strconv"
)
func main() {
s := "00000000000000000000000000001011"
fmt.Println(s)
u64, err := strconv.ParseUint(s, 2, 32)
u32 := uint32(u64)
if err == nil {
fmt.Println(u32)
}
}
Playground: https://play.golang.org/p/yiicgWsb7B_M
Output:
00000000000000000000000000001011
11

Interface variable conversion in Golang

I have a variable which value can be string or int depend on the input. I use interface{} as the type. How to convert the value of that variable to int if the input is like "50", "45", or any string of int.
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 0
if limit != "ALL" {
log.Println("INSIDE")
offset = limit.(int)*page - limit.(int)
}
fmt.Println(offset)
}
Above code got:
interface conversion: interface {} is string, not int
If I use this:
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 0
if limit != "ALL" {
log.Println("INSIDE")
offset = strconv.Atoi(limit)*page - strconv.Atoi(limit)
}
fmt.Println(offset)
}
I got this
exit status 2
command-line-arguments
./main.go:14:24: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:24: multiple-value strconv.Atoi() in single-value context
./main.go:14:51: cannot use limit (type interface {}) as type string in argument to strconv.Atoi: need type assertion
./main.go:14:51: multiple-value strconv.Atoi() in single-value context
How to convert value of that variable to int?
In Go, in contrast to languages such as Python/JavaScript/Perl, the variables have strict types and strong boundaries. You have to write explicit code to make the conversion of a string from/to an integer. This is helpful to write safer and more performant programs.
In addition, if the variable is stored in an interface{} you have to use a type assertion (or a type switch) to further use the content with a specific type.
Here is your fixed code:
package main
import "fmt"
import "log"
import "strconv"
func main() {
var limit interface{}
limit = "50"
page := 1
offset := 3
if limit != "ALL" {
// Type assertion
s, isString := limit.(string)
if !isString {
log.Fatalf("limit is not a string but %T", limit)
}
// Conversion from string to int, with error handling
l, err := strconv.Atoi(s)
if err != nil {
log.Fatalf("%s: %v", limit, err)
}
offset = l*page - l
}
fmt.Println(offset)
}
However, I suggest that you just use the string type for the limit variable.
strconv package can use for this kind of conversion
package main
import (
"fmt"
"strconv"
)
func main() {
var lim interface{}
lim = "10"
fmt.Printf("Type is: %T\nValue is: %s \n", lim, lim.(string))
i, _ := strconv.Atoi(lim.(string))
fmt.Printf("After conversion value is: %d", i)
}
Output of the above code:
Type is: string, Value is: 10
After conversion value is: 10
As I understood your question, value of your limit in fact is always string, but in one case it's value == ALL, otherwise it's a string representation of an integer value.
If I'm right, then I would provide following solution:
import (
"errors"
"fmt"
"strconv"
)
func getOffset(limit string, page int64) (int64, error) {
lim, err := strconv.ParseInt(limit, 10, 64)
if err != nil {
if limit == "ALL" {
return 0, nil
}
return 0, errors.New(fmt.Sprintf("string '%v' doesn't fit requirements, error: %v", limit, err))
}
offset := lim*page - lim
return offset, nil
}
Full solution on playground: https://play.golang.org/p/fJv9_cw18R5

I cannot access err.Err from strconv package

I am probably missing something really simple here:
package main
import (
"fmt"
"strconv"
"reflect"
)
func main() {
s := "abd"
fmt.Println(s)
_, err := strconv.Atoi(s)
if err != nil {
fmt.Println(err)
}
fmt.Println(reflect.TypeOf(err))
fmt.Println(err.Err)
}
I am trying to extract the error itself e.g. ErrSyntax or ErrRange, but I am not able to do so.
After looking at:
https://golang.org/src/strconv/atoi.go?s=3604:3671#L16
I see that err is a pointer to strconv.NumError
15 // A NumError records a failed conversion.
16 type NumError struct {
17 Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
18 Num string // the input
19 Err error // the reason the conversion failed (ErrRange, ErrSyntax)
20 }
And Err is the field that holds either ErrRange of ErrSyntax. Therefore, I thought that err.Err would work, but I get:
err.Err undefined (type error has no field or method Err
Err is public, am I missing something with visibility rules?
What am I missing?
Use a type assertion to get the *strconv.NumError value:
if e, ok := err.(*strconv.NumError); ok {
fmt.Println("e.Err", e.Err)
}
playground example

How to scan a big.Int from standard input in Go

Is there a way to scan a big.Int directly from the standard input in Go? Right now I'm doing this:
package main
import (
"fmt"
"math/big"
)
func main() {
w := new(big.Int)
var s string
fmt.Scan(&s)
fmt.Sscan(s, w)
fmt.Println(w)
}
I also could have used .SetString. But, is there a way to Scan the big.Int directly from the standard input without scanning a string or an integer first?
For example,
package main
import (
"fmt"
"math/big"
)
func main() {
w := new(big.Int)
n, err := fmt.Scan(w)
fmt.Println(n, err)
fmt.Println(w.String())
}
Input (stdin):
295147905179352825857
Output (stdout):
1 <nil>
295147905179352825857
As far as I know - no, there's no other way. In fact, what you've got is the default example they have for scanning big.Int in the documentation.
package main
import (
"fmt"
"log"
"math/big"
)
func main() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
i := new(big.Int)
_, err := fmt.Sscan("18446744073709551617", i)
if err != nil {
log.Println("error scanning value:", err)
} else {
fmt.Println(i)
}
}
You can see the relevant section here - http://golang.org/pkg/math/big/#Int.Scan

Go precise decimals with mgo

I am writing an application where I use money and want very accurate numbers. I am also using mgo to store the results after some application. I was wondering if there was a way for me to use math.Rat or godec in a struct and have it store as a number in mgo?
This is the kind of code i was hoping to run:
package main
import(
"fmt"
"math/big"
"labix.org/v2/mgo"
)
var mgoSession *mgo.Session
type Test struct{
Budget big.Rat
}
func MongoLog(table string, pointer interface{}) {
err := mgoSession.DB("db_log").C(table).Insert(pointer)
if err != nil {
panic(err)
}
}
func main(){
var err error
mgoSession, err = mgo.Dial("localhost:27017")
defer mgoSession.Close()
if err != nil {
panic(err)
}
cmp := big.NewRat(1, 100000)
var test = Test{Budget : *big.NewRat(5, 10)}
MongoLog("test", &test)
for i := 0; i < 20; i++{
fmt.Printf("Printf: %s\n", test.Budget.FloatString(10))
fmt.Println("Println:", test.Budget, "\n")
test.Budget.Sub(&test.Budget, cmp)
// test.Budget = test.Budget - cpm
}
MongoLog("test", &test)
}
big.Rat is basically a pair of unexported int big.Int values describing the numerator and denominator of a rational number, respectively.
You can easily get both numbers through (*big.Rat).Denom and (*big.Rat).Num.
Then store them in a structure of your own, with exported (upper case) fields:
type CurrencyValue struct {
Denom int64
Num int64
}
Store this with mgo and convert it back to a *big.Rat in your application through big.NewRat
Edit:
Nick Craig-Wood in the comments correctly noted that big.Rat actually consists of 2 big.Int values, not int values as I had written (easy to miss the upper case i). It's hard to represent a big.Int in BSON but, int64 should cover most use-cases.

Resources