Interface variable conversion in Golang - go

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

Related

Cannot use (type []byte) as type string in argument to strconv.ParseFloat issue

pi#raspberrypi:~/Desktop/go $ go run shell1.go
As result i am getting:
pi#raspberrypi:~/Desktop/go $ go run shell1.go
# command-line-arguments
./shell1.go:29: undefined: n
./shell1.go:29: cannot use b (type []byte) as type string in argument to strconv.ParseFloat
./shell1.go:32: undefined: n
Go file (shell1.go) code is:
package main
import (
// "net/http"
// "github.com/julienschmidt/httprouter"
"fmt"
"log"
"os/exec"
"strconv"
"time"
//"bytes"
//"encoding/binary"
)
import _ "github.com/go-sql-driver/mysql"
import _ "database/sql"
func main() {
for {
time.Sleep(10 * time.Millisecond)
cmd := exec.Command("gpio.bash")
b, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
n, _ = strconv.ParseFloat(b, 10)
fmt.Println(string(b))
break
}
fmt.Println("Button pressed!!! ", n)
}
Content of (gpio.bash) file is just one command to read gpio
#!/bin/bash
gpio read 29
You are working with a command here, which can of course execute just about anything.
The function is purposely generic, as the true return type varies depending on what you executed. Thus, when you call the output method, you are given a slice of bytes (very generic!). Here is its signature:
func (c *Cmd) Output() ([]byte, error)
If you know that the bytes will always be a string, then you simply have to do a type conversion to a string:
n, _ := strconv.ParseFloat(string(b), 10)

using reflection in Go to get the name of a struct

I found this question with this great answers:
How to find a type of a object in Golang?
I played around with the answer and tried to get the name of a struct in the same way:
package main
import (
"fmt"
"reflect"
)
type Ab struct {
}
func getType(myvar interface{}) string {
return reflect.TypeOf(myvar).Name()
}
func main() {
fmt.Println("Hello, playground")
tst := "string"
tst2 := 10
tst3 := 1.2
tst4 := new(Ab)
fmt.Println(getType(tst))
fmt.Println(getType(tst2))
fmt.Println(getType(tst3))
fmt.Println(getType(tst4))
}
Go playground: http://play.golang.org/p/tD8mygvETH
But the output is:
Hello, playground
string
int
float64
Program exited.
Expected output would be:
Hello, playground
string
int
float64
Ab
Program exited.
I tried to figure out by reading the documentation but didn't find the issue about that. So, sorry for the very general question, but:
What's the reason, reflect.TypeOf().Name() does not work with (this) struct(s)?
In your example you pass a value of pointer type (*Ab), not a struct type.
Sticking to Type.Name()
If it is not a pointer, Type.Name() will properly return Ab. In case of pointer if you still want the struct's name, you can use Type.Elem() to get the element's type:
func getType(myvar interface{}) string {
if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr {
return "*" + t.Elem().Name()
} else {
return t.Name()
}
}
Testing it:
tst4 := Ab{}
tst5 := new(Ab)
fmt.Println(getType(tst4))
fmt.Println(getType(tst5))
Output (try your modified example on the Go Playground):
Ab
*Ab
Note:
Note that as Type.Name() does not resolve pointers, it would not work if the value passed is a pointer to pointer, e.g. **Ab, while as Type.String() automatically resolves pointers, would work in this case too.
We can easily make our getType() function to work with **Ab too (or with any depth of pointers):
func getType(myvar interface{}) (res string) {
t := reflect.TypeOf(myvar)
for t.Kind() == reflect.Ptr {
t = t.Elem()
res += "*"
}
return res + t.Name()
}
Calling it with values:
tst4 := Ab{}
tst5 := new(Ab)
tst6 := &tst5 // type of **Ab
tst7 := &tst6 // type of ***Ab
Output (try it on the Go Playground):
Ab
*Ab
**Ab
***Ab
Using Type.String()
A simpler and better approach would be to use Type.String() instead of Type.Name() which automatically handles pointers and also includes package name. E.g.:
func getType(myvar interface{}) string {
return reflect.TypeOf(myvar).String()
}
For the modified example it outputs:
string
int
float64
main.Ab
*main.Ab
Try this variant on the Go Playground.
fmt has a cool %T tag as well
package main
import (
"fmt"
"net/http"
)
type Potato struct {
}
func main() {
fmt.Printf("I have a %T, an %T and a %T\n", Potato{}, http.StatusMultipleChoices, &http.Response{})
}
outputs I have a main.Potato, an int and a *http.Response
https://play.golang.org/p/6z7_0BSitm
The problem is new returns pointer, following should get the desired result.
package main
import (
"fmt"
"reflect"
)
type Ab struct {
}
func getType(myvar interface{}) {
valueOf := reflect.ValueOf(myvar)
if valueOf.Type().Kind() == reflect.Ptr {
fmt.Println(reflect.Indirect(valueOf).Type().Name())
} else {
fmt.Println(valueOf.Type().Name())
}
}
func main() {
fmt.Println("Hello, playground")
tst := "string"
tst2 := 10
tst3 := 1.2
tst4 := new(Ab)
getType(tst)
getType(tst2)
getType(tst3)
getType(tst4)
}
Output is
Hello, playground
string
int
float64
Ab

Difference between []uint8 && []byte (Golang Slices)

One of the functions I am running: image.Decode()
The image.Decode function takes in an io.Reader && and the io.Reader function takes in a []byte.
When I pass in a []uint8, if gives me this error:
panic: image: unknown format
How do I convert the []uint8 to []byte?
UPDATE
The error is happening at the starred area because image.Decode can't read the variable xxx.
package main
import (
"github.com/nfnt/resize"
"image"
"image/jpeg"
"fmt"
"launchpad.net/goamz/aws"
"launchpad.net/goamz/s3"
"bytes"
"encoding/json"
"io/ioutil"
"os"
"reflect"
)
type Data struct {
Key string
}
func main() {
useast := aws.USEast
connection := s3.New(auth, useast)
mybucket := connection.Bucket("bucketName")
image_data, err := mybucket.Get("1637563605030")
if err != nil {
panic(err.Error())
} else {
fmt.Println("success")
}
xxx := []byte(image_data)
******* THIS IS WHERE THE ERROR OCCURS **************
original_image, _, err := image.Decode(bytes.NewReader(xxx))
******* THIS IS WHERE THE ERROR OCCURS END **************
if err != nil {
fmt.Println("Shit")
panic(err.Error())
} else {
fmt.Println("Another success")
}
new_image := resize.Resize(160, 0, original_image, resize.Lanczos3)
if new_image != nil {
fmt.Println("YAY")
}
}
The Go Programming Language Specification
Numeric types
uint8 the set of all unsigned 8-bit integers (0 to 255)
byte alias for uint8
package main
import "fmt"
func ByteSlice(b []byte) []byte { return b }
func main() {
b := []byte{0, 1}
u8 := []uint8{2, 3}
fmt.Printf("%T %T\n", b, u8)
fmt.Println(ByteSlice(b))
fmt.Println(ByteSlice(u8))
}
Output:
[]uint8 []uint8
[0 1]
[2 3]
You have misdiagnosed your problem.
As the other answers have explained, there's no problem passing a []uint8 where a []byte is required. If this was your problem, you'd be getting a compile time error. You aren't. A panic is a runtime error, and it's being thrown by the image library when it reads the data in the slice.
In fact, the image library is only partially your problem. See http://golang.org/src/pkg/image/format.go. It's returning an error message because it doesn't recognize the image format of the data in the slice. Your code, which calls image.Decode() is calling panic when image.Decode() returns the error message.
If you have a variable imageData that is []uint8 you may pass []byte(imageData)
See http://golang.org/ref/spec#Conversions

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

Convert from string to int (and throw error if unsuccessful)

My apologies if this is a beginner question, but I simply can't seem to find any solution for this. I'm trying to take an argument that can be either a string or an int, depending on the context, and I need to determine which type, (then convert it to int if it is indeed that type.)
Thank you :)
For example,
package main
import (
"errors"
"fmt"
"strconv"
)
func IntConv(arg interface{}) (int, error) {
switch x := arg.(type) {
case int:
return x, nil
case string:
return strconv.Atoi(x)
}
return 0, errors.New("IntConv: invalid argument ")
}
func main() {
fmt.Println(IntConv(7))
fmt.Println(IntConv("42"))
}
http://golang.org/pkg/strconv/#Atoi
func Atoi
func Atoi(s string) (i int, err error)
Atoi is shorthand for ParseInt(s, 10, 0).
This is an update. To clarify, since Atoi accepts string, then trying to pass an int will cause a compile time error. If you need a check during runtime, then you can do something like this.
package main
import (
"fmt"
"strconv"
"errors"
)
func toInt(data interface{}) (n int, err error) {
switch t := data.(type) {
case int:
return t, nil
case string:
return strconv.Atoi(t)
default:
return 0, errors.New(fmt.Sprintf("Invalid type received: %T", t))
}
panic("unreachable!")
}
func main() {
var (
n int
err error
)
n, _ = toInt("1")
fmt.Println(n)
n, _ = toInt(2)
fmt.Println(n)
n, err = toInt(32.3)
fmt.Println(err)
}
I'm a bit late to the party, but you could also use fmt.Sprintf:
import "fmt"
func ConvertToString(x interface{}) string {
return fmt.Sprintf("%v", x)
}
Passing "%v" to Sprintf tells it to format it using the best format it knows, which essentially just means "convert x to a string". This is shorter (and perhaps easier to understand) than the other solutions, but has the disadvantage that it'll allow inputs that aren't ints or strings.

Resources