Cannot unmarshal simple Date - go

I am starting A tour of Go, but I am experimenting on the way.
I wrote a piece of code:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
actualTime := time.Now()
fmt.Println(actualTime)
var marshalledtime []byte
marshalledtime,_ := actualTime.MarshalJSON()
fmt.Println(marshalledtime)
actualTime := (*time.Time).UnmarshalJSON(marshalledtime)
fmt.Println(actualTime)
}
I just wanted to marshal a simple date, and then unmarshal it to just see the process.
But I am completely overhelmed with problems. Up to today GO seemed to be so simple and logical, but now... I don't know, I am stuck.
./compile219.go:27:13: cannot use time.(*Time).UnmarshalJSON(marshalledtime) (type error) as type time.Time in assignment
./compile219.go:27:42: not enough arguments in call to method expression time.(*Time).UnmarshalJSON
have ([]byte)
want (*time.Time, []byte)
Why does the last error mean? The documentation clearly says that UnmarshalJson takes only one argument, byte[].
What is with the type conversion error?

actualTime.MarshalJSON() is a method call, it calls the Time.MarshalJSON() method. It returns you the bytes of the JSON representation of the time. Since the bytes printed are not well readable, you should print the byte slice as a string, e.g.:
fmt.Println("Raw:", marshalledtime)
fmt.Println("String:", string(marshalledtime))
Which outputs:
Raw: [34 50 48 48 57 45 49 49 45 49 48 84 50 51 58 48 48 58 48 48 90 34]
String: "2009-11-10T23:00:00Z"
UnmarshalJSON() is also a method of time.Time, so you need a time.Time value to call it "on", for example:
var time2 time.Time
time2.UnmarshalJSON(marshalledtime)
(To be precise, UnmarshalJSON() requires a pointer of type *time.Time because it has to modify the time.Time value, but the Go compiler will rewrite time2.UnmarshalJSON() to take time2's address: (&time2).UnmarshalJSON()).
MarshalJSON() and UnmarshalJSON() also return an error which you should always check, for example:
var marshalledtime []byte
var err error
marshalledtime, err = actualTime.MarshalJSON()
if err != nil {
panic(err)
}
And:
var time2 time.Time
err = time2.UnmarshalJSON(marshalledtime)
if err != nil {
panic(err)
}
Try the fixed code on the Go Playground.
Also note that it's rare that someone calls Time.MarshalJSON() and Time.UnmarshalJSON() "by hand". They are to implement the json.Marshaler and json.Unmarshaler interfaces, so when you marshal / unmarshal time values, the encoding/json package will call these methods to do the JSON conversion.
This is how the same can be achieved using the encoding/json package (try it on the Go Playground):
Marshaling:
var marshalledtime []byte
var err error
marshalledtime, err = json.Marshal(actualTime)
if err != nil {
panic(err)
}
Unmarshaling:
var time2 time.Time
err = json.Unmarshal(marshalledtime, &time2)
if err != nil {
panic(err)
}
Although it's not simpler or shorter in this case, the encoding/json package is capable of marshaling / unmarshaling arbitrary complex data structures, not just simple time values.

The documentation clearly says that UnmarshalJson takes only one argument, byte[]
UnmarshalJson is the method in case you want to redefine the behavior of Unmarshal on a struct. That's not the case here. You don't have to use it unless you want to customize Unmarshal. Then UnmarshalJson will be called under the hood when you will make a call to Unmarshal
By the way, if you see the signature of UnmarshalJson you will see that it does return only an error.
Here is a fix using json.Unmarshal
package main
import (
"fmt"
"encoding/json"
"time"
)
func main() {
actualTime := time.Now()
fmt.Println(actualTime)
var marshalledtime []byte
marshalledtime,_ = actualTime.MarshalJSON()
fmt.Println(marshalledtime)
json.Unmarshal(marshalledtime, &actualTime)
fmt.Println(actualTime)
}

Related

go-redis Eval func return value type, when Lua script returns an array

When a Lua script returns a table array during an Eval call, how can it be converted to a []string in go?
The redis cli returns bulk replies in the following format.
1) val1
2) val2
Will go-redis eval function return the bulk entries as
["val1", "val2"]
Redis returns Lua table arrays as RESP2 arrays. The Go client then will map that response to Go native types. The relevant documentation for go-redis is found here: Lua and Go types.
The tl;dr is that Lua tables are indeed mapped to a bulk reply, and the Go client maps that to a slice of interface: []interface{}.
Both go-redis script Run and Eval return a *Cmd. You can use methods on this type to retrieve the output as Go types. Result gives (interface{}, error), which you can type-assert to whatever you want, otherwise, StringSlice is a convenience getter to retrieve []string right away.
So it looks like:
script := redis.NewScript(`
local foo = {"val1", "val2"}
return foo
`)
cmd := script.Run(/* parameters */)
i, err := cmd.Result() // (interface, error)
// or
ss, err := cmd.StringSlice() // ([]string, error)
If the values aren't actually all strings, use Slice to get the []interface{} slice, and then inspect the elements individually.
You can use the encoding/json package to convert a JSON string to a slice of strings.
package main
import (
"encoding/json"
"fmt"
)
// jsonString is the JSON string that you want to convert to a slice of strings.
const jsonString = `["value1", "value2"]`
func main() {
var stringSlice []string
// Unmarshal the JSON string into the stringSlice variable.
err := json.Unmarshal([]byte(jsonString), &stringSlice)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(stringSlice) // ["value1", "value2"]
}

How do you pass a slice of *interface{} as arguments?

I want to use Scan() in package sql, but the number of columns, and hence the number of arguments, will change at runtime. This is the signature of Scan():
func (rs *Rows) Scan(dest ...interface{}) error
According to the documentation, *interface{} is one of the types accepted by Scan(). So I want to create a slice of []*interface{} and that expand as arguments.
This is what I thought would work:
func query(database *sql.DB) {
rows, _ := database.Query("select * from testTable")
for rows.Next() {
data := make([]*interface{}, 2)
err := rows.Scan(data...) // Compilation error
fmt.Printf("%v%v\n", *data[0], *data[1])
if err != nil {
fmt.Println(err.Error())
}
}
}
Compilation fails with cannot use data (type []*interface {}) as type []interface {} in argument to rows.Scan. I thought that data... would expand to &data[0], &data[1], but apparently not. I don't understand the error message. *interface{} is compatible with interface{}, so why can't I expand the slice of pointers to interface types?
This works:
func query(database *sql.DB) {
rows, _ := database.Query("select * from testTable")
for rows.Next() {
data := make([]*interface{}, 2)
err := rows.Scan(&data[0], &data[1]) // Only changed this line
fmt.Printf("%v%v\n", *data[0], *data[1]) // Outputs "[48][116 101 120 116]"
if err != nil {
fmt.Println(err.Error())
}
}
}
I can't use this however, because the number of columns is unknown at compile time. How can I write this code so that I can pass a variable number of *interface{} to rows.Scan()?
First, you must not use []*interface{} slice of pointers to interface rather than []interface{} where the interfaces are pointers. []*interface{} is different from []interface{}. Just create a slice of interfaces where each element is a pointer to a concrete type.
Here is a snippet how you would do this.
var x int
var s string
data := []interface{}{&x, &s}
rows.Scan(data...)
Note on the use of the ... spread operator.
Here are some related questions that will explain a bit more:
golang: slice of struct != slice of interface it implements?
Cannot convert []string to []interface {}
If you really want to pass a []*interface{} (perhaps you don't know the concrete types of the output) you must first wrap each *interface{} in a interface{}:
values := make([]interface{}, columnsCount)
for i := range values {
values[i] = new(interface{})
}
Individual values passed into a ...interface{} parameter are automatically wrapped in a interface{}, but just like []int... won't satisfy ...interface{}, neither will []*interface{}....

How can I convert a JSON string to a byte array?

I need some help with unmarshaling. I have this example code:
package main
import (
"encoding/json"
"fmt"
)
type Obj struct {
Id string `json:"id"`
Data []byte `json:"data"`
}
func main() {
byt := []byte(`{"id":"someID","data":["str1","str2"]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Println(obj)
}
What I try to do here - convert bytes to the struct, where type of one field is []byte. The error I get:
panic: json: cannot unmarshal string into Go struct field Obj.data of
type uint8
That's probably because parser already sees that "data" field is already a slice and tries to represent "str1" as some char bytecode (type uint8?).
How do I store the whole data value as one bytes array? Because I want to unmarshal the value to the slice of strings later. I don't include a slice of strings into struct because this type can change (array of strings, int, string, etc), I wish this to be universal.
My first recommendation would be for you to just use []string instead of []byte if you know the input type is going to be an array of strings.
If data is going to be a JSON array with various types, then your best option is to use []interface{} instead - Go will happily unmarshal the JSON for you and you can perform checks at runtime to cast those into more specific typed variables on an as-needed basis.
If []byte really is what you want, use json.RawMessage, which is of type []byte, but also implements the methods for JSON parsing. I believe this may be what you want, as it will accept whatever ends up in data. Of course, you then have to manually parse Data to figure out just what actually IS in there.
One possible bonus is that this skips any heavy parsing because it just copies the bytes over. When you want to use this data for something, you use a []interface{}, then use a type switch to use individual values.
https://play.golang.org/p/og88qb_qtpSGJ
package main
import (
"encoding/json"
"fmt"
)
type Obj struct {
Id string `json:"id"`
Data json.RawMessage `json:"data"`
}
func main() {
byt := []byte(`{"id":"someID","data":["str1","str2", 1337, {"my": "obj", "id": 42}]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Printf("%+v\n", obj)
fmt.Printf("Data: %s\n", obj.Data)
// use it
var d []interface{}
if err := json.Unmarshal(obj.Data, &d); err != nil {
panic(err)
}
fmt.Printf("%+v\n", d)
for _, v := range d {
// you need a type switch to deterine the type and be able to use most of these
switch real := v.(type) {
case string:
fmt.Println("I'm a string!", real)
case float64:
fmt.Println("I'm a number!", real)
default:
fmt.Printf("Unaccounted for: %+v\n", v)
}
}
}
Your question is:
convert bytes array to struct with a field of type []byte
But you do not have a bytearray but a string array. Your question is not the same as your example. So let answer your question, there are more solutions possible depending in how far you want to diverge from your original requirements.
One string can be converted to one byte-slice, two strings need first to be transformed to one string. So that is problem one. The second problem are the square-brackets in your json-string
This works fine, it implicitly converts the string in the json-string to a byte-slice:
byt := []byte(`{"id":"someID","data":"str1str2"}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Println(obj)

How we can know what kind of struct is on byte array

I'm looking for some solution to know whats the struct type of the hash. It is possible to do that without try an error method (casting to a specific type and see the cast is successfully)?
Please check the code:
import (
"bytes"
"encoding/binary"
"fmt"
"reflect"
)
type T struct {
A int64
B float64
}
type D struct {
A int64
B float64
C string
}
func main() {
// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
buf := &bytes.Buffer{}
err := binary.Write(buf, binary.BigEndian, t)
if err != nil {
panic(err)
}
fmt.Println(buf.Bytes())
out := getType(buf)
fmt.Println(out)
}
func getType(v interface{})(r string){
fmt.Println(reflect.TypeOf(v))
switch t := v.(type) {
case T:
return "Is type T"
case D:
return "Is type D"
default:
_ = t
return "unknown"
}
}
Since the encoding/binary package does not write out type information, it is not possible to tell what type was written / serialized.
And you're in a worse position that you might originally think: even trying to decode into a value of different type might succeed without errors, so there isn't even a reliable way to tell the type.
For example if you serialize a value of this type:
type T struct {
A int64
B float64
}
You can read it into a value of this type:
type T2 struct {
B float64
A int64
}
It will give no errors because the size of both structs is the same, but obviously you will get different numbers in the fields.
You are in a little better position if you use encoding/gob, as the gob package does transmit type information, and encoding a value of type T and then decoding it into a value of type T2 would work: order of fields does not matter, and extra or missing fields also do not cause trouble.
See this example:
// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
fmt.Println("Encoding:", t)
buf := &bytes.Buffer{}
fmt.Println(binary.Write(buf, binary.BigEndian, t))
fmt.Println(buf.Bytes())
fmt.Println(gob.NewEncoder(buf).Encode(t))
t2 := T2{}
fmt.Println(binary.Read(buf, binary.BigEndian, &t2))
fmt.Println(t2)
t2 = T2{}
fmt.Println(gob.NewDecoder(buf).Decode(&t2))
fmt.Println(t2)
Output (try it on the Go Playground):
Encoding: {4009750271 3.14}
<nil>
[0 0 0 0 238 255 238 255 64 9 30 184 81 235 133 31]
<nil>
<nil>
{1.9810798573e-314 4614253070214989087}
<nil>
{3.14 4009750271}
If you want to be able to detect the type before reading it, you have to take care of it yourself: you have to transmit type information (e.g. name of the type). Or even better, use a serialization method that already does this, for example Google's protocol buffers, and here is the Go implementation for it: github.com/golang/protobuf.

cannot convert data (type interface {}) to type string: need type assertion

I am pretty new to go and I was playing with this notify package.
At first I had code that looked like this:
func doit(w http.ResponseWriter, r *http.Request) {
notify.Post("my_event", "Hello World!")
fmt.Fprint(w, "+OK")
}
I wanted to append newline to Hello World! but not in the function doit above, because that would be pretty trivial, but in the handler afterwards like this below:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
fmt.Fprint(w, data + "\n")
}
After go run:
$ go run lp.go
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)
After a little bit of Googling I found this question on SO.
Then I updated my code to:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
s:= data.(string) + "\n"
fmt.Fprint(w, s)
}
Is this what I was supposed to do? My compiler errors are gone so I guess that's pretty good? Is this efficient? Should you do it differently?
According to the Go specification:
For an expression x of interface type and a type T, the primary expression x.(T) asserts that x is not nil and that the value stored in x is of type T.
A "type assertion" allows you to declare an interface value contains a certain concrete type or that its concrete type satisfies another interface.
In your example, you were asserting data (type interface{}) has the concrete type string. If you are wrong, the program will panic at runtime. You do not need to worry about efficiency, checking just requires comparing two pointer values.
If you were unsure if it was a string or not, you could test using the two return syntax.
str, ok := data.(string)
If data is not a string, ok will be false. It is then common to wrap such a statement into an if statement like so:
if str, ok := data.(string); ok {
/* act on str */
} else {
/* not string */
}
Type Assertion
This is known as type assertion in golang, and it is a common practice.
Here is the explanation from a tour of go:
A type assertion provides access to an interface value's underlying concrete value.
t := i.(T)
This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t.
If i does not hold a T, the statement will trigger a panic.
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.
t, ok := i.(T)
If i holds a T, then t will be the underlying value and ok will be true.
If not, ok will be false and t will be the zero value of type T, and no panic occurs.
NOTE: value i should be interface type.
Pitfalls
Even if i is an interface type, []i is not interface type. As a result, in order to convert []i to its value type, we have to do it individually:
// var items []i
for _, item := range items {
value, ok := item.(T)
dosomethingWith(value)
}
Performance
As for performance, it can be slower than direct access to the actual value as show in this stackoverflow answer.
//an easy way:
str := fmt.Sprint(data)
As asked for by #ρяσѕρєя an explanation can be found at https://golang.org/pkg/fmt/#Sprint. Related explanations can be found at https://stackoverflow.com/a/44027953/12817546 and at https://stackoverflow.com/a/42302709/12817546. Here is #Yuanbo's answer in full.
package main
import "fmt"
func main() {
var data interface{} = 2
str := fmt.Sprint(data)
fmt.Println(str)
}
In addition to other answers, I think it's good to have a look at "type switch":
package main
import "fmt"
func printType(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("type of %v is %v\n", i, v)
// type of 21 is int
case string:
fmt.Printf("type of %v is %v\n", i, v)
// type of hello is string
default:
fmt.Printf("type of %v is %v\n", i, v)
// type of true is bool
}
}
func main() {
printType(21)
printType("hello")
printType(true)
}
I hope it helps.
More information: https://go.dev/tour/methods/16

Resources