Original question:
I'm trying to do some deserialization and I'm a little confused about how to access a struct when passing in an interface.
package main
import (
"fmt"
"reflect"
)
type Robot struct {
Id int
}
func f(i interface{}) {
v := reflect.ValueOf(i).Elem().FieldByName("Id")
fmt.Println("fields: ", reflect.ValueOf(i).Elem().NumField())
ptr := v.Addr().Interface().(*int)
*ptr = 100
}
func main() {
robot := Robot{}
var iface interface{} = robot // if I omit this line and pass in robot this works
f(&iface)
fmt.Println(robot.Id) //I want to get here 100
}
http://play.golang.org/p/y6UN3KZxRB
The play example works if you just pass in the struct directly, however as it's possible for anything to be passed in that implements a specific interface (in my example case I'm just using the empty interface). However I can't figure out how to then treat it as a struct underneath.
Updated:
package main
import (
"fmt"
"reflect"
)
type MessageOne struct {
Header string `FixedWidth:0,4`
FieldOne string `FixedWidth:"4,4"`
FieldTwo string `FixedWidth:"8,4"`
}
type MessageTwo struct {
FieldX string `FixedWidth:"X,Y"`
FieldY string `FixedWidth:"X,Y"`
}
var (
messageMap = map[string]interface{}{
"msg1": MessageOne{FieldOne: "testValueUnchanged"},
"msg2": MessageTwo{},
}
)
func deserialize(input string, i interface{}) interface{} {
value := reflect.ValueOf(i)
fmt.Println("1st Value Type: ", value.Kind())
// unswarp ptr
value = value.Elem()
fmt.Println("Unwrapped: ", value.Kind())
value = value.Elem()
fmt.Println("Unwrapped: ", value.Kind())
// Create a copy that I can set?
copyValue := reflect.New(value.Type()).Elem()
fmt.Println("Orig Struct is settable", value.CanSet())
fmt.Println("Orig StructField0 is settable", value.Field(0).CanSet())
fmt.Println("Copy is: ", copyValue.Kind())
fmt.Println("Copy Struct is settable", copyValue.CanSet())
fmt.Println("Copy StructField0 is settable", copyValue.Field(0).CanSet())
fmt.Println("Orig struct type is: ", value.Type())
fmt.Println("Copy struct type is: ", copyValue.Type())
copyValue.Field(1).SetString("testValueChanged")
return copyValue.Interface()
}
func GetMessageFromInput(input string) interface{} {
selector := input[0:4]
fmt.Println(selector)
field := messageMap[selector]
return deserialize(input, &field)
}
func main() {
val := messageMap["msg1"]
serializedData := "msg1.012345678"
deserializedVal := GetMessageFromInput(serializedData)
//msg1 := deserializedVal.(MessageOne)
fmt.Printf("Orig: %+v \nReceived: %+v", val, deserializedVal)
}
http://play.golang.org/p/Cj9oPPGSLM
I got the idea of copying my struct and thereby getting an addressable instance from here: https://gist.github.com/hvoecking/10772475
So I guess my question is now, is there a mechanism to access an addressable / settable struct without having to resort to a copy?
The underlying problem is taking strings (byte arrays really) and having a struct have the necessary info to effectively deserialize it without having to write a couple dozen deserialization functions which would suck to maintain. So the tags in those sample structs aren't addressed in the sample question, but accessing the structs tag fields would provide the offsets from which to populate the struct from the input bytes. Obviously I haven't gotten that far. Part of my frustration here is that it seems I've worked very hard to not get very far and I don't feel like i've learned much in the process.
Some additional play edits that got me my tags back:
http://play.golang.org/p/2DbbWLDKPI
You don't want to pass a pointer to the interface, you want to pass in a pointer to your struct itself.
robot := &Robot{}
f(robot)
http://play.golang.org/p/owv-Y4dnkl
The moment you assigned robot to iface, you created a copy of the robot value. There's is no way to ever get a reference back to robot from iface.
When you pass in f(&iface), the call to reflect.ValueOf(i).Elem() is just returning the inner iface value, not a Robot struct value.
In your original code, use:
var iface interface{} = &robot
f(iface)
Explanation
In the original version, we are sending in the address of the interface variable (which is a copy of the robot). This sends a pointer of type interface, and so reflect works on the copy of the robot.
var iface interface{} = robot
f(&iface)
What we need to do, is assign a pointer of type robot to the interface variable. Thus, when we send the interface we are sending the pointer of type robot, so reflect works with the actual robot object and not a copy.
var iface interface{} = &robot
f(iface)
You could use Type Assertion.
value, ok := i(Robot)
if ok {
fmt.Println(value.Id)
}
From this stackoverflow post.
Related
I have a map of type set, which is actually a map[string]string. However, passing it to a function which accepts a map[string]string fails, because Go does not recognize set as one.
However, I fail to convince the compiler it is one. Is there any way to resolve this, without looping and copying?
package main
import (
"fmt"
)
type name string
type field string
type set map[name]field // map[string]string after all
type plain map[string]string // also map[string]string
func main() {
var typed = set{"hi": "ho"} // map[string]string?
back := plain(typed) // cannot convert typed (type set) to type plain
back := typed.(plain) // invalid type assertion: typed.(plain) (non-interface type set on left)
echo(back)
}
func echo(in map[string]string) {
fmt.Println(in)
}
You could do this using the unsafe package.
Note: I don't think this would necessarily be a good idea, and probably the right way would be to just iterate and copy, but since it does answer the question asked...
var typed = set{"hi": "ho"} // map[string]string?
p := unsafe.Pointer(&typed)
var back plain
back = *(*plain)(p)
Playground: https://play.golang.org/p/yienSuJSnQU
I have the following code and I want to use interfaces:
Current code:
import (
"github.com/dorzheh/deployer/ui/dialog_ui"
. "github.com/dorzheh/go-dialog"
)
// all methods in https://github.com/dorzheh/deployer/blob/master/ui/dialog_ui/dialog_ui.go#L28
type Pb struct {
sleep time.Duration
step int
}
type DialogUi struct {
*Dialog //The source is https://github.com/dorzheh/go-dialog/blob/master/dialog.go#L34
Pb *Pb
}
I am trying to implement interfaces this way:
import (
"testing"
// . "github.com/dorzheh/go-dialog"
//"github.com/dorzheh/deployer/ui/dialog_ui"
)
type PBifaceT interface {
Step() int
}
type TestDialogUiT struct {
Pb *PBifaceT
}
func TestUiValidateUser(t *testing.T) {
x := dialog_ui.TestDialogUiT{}
PbPb := ImplPBifaceT{}
x.Pb = PbPb
parentId := x.Pb.Step()
t.Logf(fmt.Sprintf("%v", parentId))
}
I've made a playground. As you can see it runs in the following error:
prog.go:23: cannot use PbPb (type ImplPBifaceT) as type *PBifaceT in assignment:
*PBifaceT is pointer to interface, not interface
prog.go:25: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)
I tried to convert them in this playground:
func NewD() *PBifaceT {
// var err error
var res =new(ImplPBifaceT)
return (*PBifaceT)(res)
}
func main() {
x := TestDialogUiT{}
x.Pb = NewD()
parentId := x.Pb.Step()
fmt.Sprintf("%v", parentId)
}
The issue:
prog.go:23: cannot convert res (type *ImplPBifaceT) to type *PBifaceT
prog.go:30: x.Pb.Step undefined (type *PBifaceT is pointer to interface, not interface)
Are you sure you need your PbĀ field as a *PBifaceT.
If you keep it as a
type TestDialogUiT struct {
Pb *PBifaceT
}
and you do
x := TestDialogUiT{}
PbPb := ImplPBifaceT{}
x.Pb = PBifaceT(PbPb)
parentId := x.Pb.Step()
fmt.Printf("%v", parentId)
It works properly..
Take a look at this playground and see if it can help.
I'd suggest you to take a look at this tutorial and this doc.
I'd suggest you also to read this SO answer which explains a bit of how you shouldn't want to use interface pointers.
Background: In Go you pass around a pointer to something because of two reasons:
1) You want because your struct is really large and you want to avoid copying
2) you need to because the calee wants to modify the original (this is typical for methods with a pointer receiver). Now an interface value is really tiny (just two words) so reason 1 to pass a pointer to an interface value does not apply.
Reason 2 does not apply in most cases as passing a pointer to an interface value will allow you to change the interface value itself, but most often you would like to modify the value stored inside the interface value. This value stored inside the interface value often is a pointer value which allows to change the value of a struct by calling methods on an interface value which wrapps a pointer to this struct. This sounds complicated but isn't: The novice Go programmer just doesn't use pointers to interfaces (as this won't do any good) and the experienced Go programmer doesn't use pointers to interfaces (as it won't do much good) unless he needs to modify an interface value, typically during reflection.
You can use Pb by link, you were just missing pointer reference while assigning.
package main
import (
"fmt"
)
type PBifaceT interface {
Step() int
}
type TestDialogUiT struct {
Pb PBifaceT
}
type ImplPBifaceT struct {
}
func (m *ImplPBifaceT) Step() int {
return 0
}
func main() {
x := TestDialogUiT{}
PbPb := &ImplPBifaceT{}
x.Pb = PbPb
parentId := x.Pb.Step()
fmt.Printf("%v", parentId)
}
Please refer this playground link: https://play.golang.org/p/N7quQFpYU0
Changes were at line 12, 17, 23 & 27.
Do not use pointer to interface unless you are sure that's what you want, see Pb *PBifaceT inside TestDialogUiT. If you change it to just Pb PBifaceT your playground link just works.
An interface is already a pointer.
Is it possible and how to get the reflect.Type of a type without creating an object from the type and calling on it reflect.TypeOf(obj)
What in java will be: MyType.class
You can achieve this without an instantiation with the following syntax;
package main
import (
"fmt"
"reflect"
)
type Test struct {
}
func main() {
fmt.Println(reflect.TypeOf((*Test)(nil)).Elem())
}
play; https://play.golang.org/p/SkmBNt5Js6
Also, it's demonstrated in the reflect example here; https://golang.org/pkg/reflect/#example_TypeOf
No you can't have it directly, because in Go structs have no accessible fields to get their type.
One may think of tweaking it by doing the following:
type object struct {}
func main() {
var obj object
t := reflect.TypeOf(object)
fmt.Println(t)
// main.object
}
However, in Go every variable is initialized with its zero value, so this is perfectly equivalent to:
t := reflect.TypeOf(object{})
// main.object
If you look at Golang's source code, you'll see that reflect.Type is an interface implemented differently according to types, however you do not have access to those informations.
But, what you can do is get the type of a pointer to the struct and from there, get the actual type. The process is the same, except that a pointer's zero value is nil, so it takes less time to instantiate:
func main() {
ptr_t := reflect.TypeOf((*object)(nil))
fmt.Println(ptr_t)
// *main.object
t := ptr_t.Elem()
fmt.Println(t)
// main.object
}
Is there a reason why I should create a struct using &StructName{} instead of Struct{}? I see many examples using the former syntax, even in the Effective Go Page but I really can not understand why.
Additional Notes:
I'm not sure whether I explained my problem well with these two approaches so let me refine my question.
I know that by using the & I will recieve a pointer instead of a value however I would like to know why would I use the &StructName{} instead of the StructName{}. For example, is there any benefits of using:
func NewJob(command string, logger *log.Logger) *Job {
return &Job{command, logger}
}
instead of:
func NewJob(command string, logger *log.Logger) Job {
return Job{command, logger}
}
Well, they will have different behavior. Essentially if you want to modify state using a method on a struct, then you will need a pointer, otherwise a value will be fine. Maybe an example will be better:
package main
import "fmt"
type test_struct struct {
Message string
}
func (t test_struct)Say (){
fmt.Println(t.Message)
}
func (t test_struct)Update(m string){
t.Message = m;
}
func (t * test_struct) SayP(){
fmt.Println(t.Message)
}
func (t* test_struct) UpdateP(m string) {
t.Message = m;
}
func main(){
ts := test_struct{}
ts.Message = "test";
ts.Say()
ts.Update("test2")
ts.Say() // will still output test
tsp := &test_struct{}
tsp.Message = "test"
tsp.SayP();
tsp.UpdateP("test2")
tsp.SayP() // will output test2
}
And you can run it here go playground
Assuming you know the general difference between a pointer and a value:
The first way allocates a struct and assigns a pointer to that allocated struct to the variable p1.
p1 := &StructName{}
The second way allocates a struct and assigns a value (the struct itself) to the variable s.
Then a pointer to that struct may be assigned to another variable (p2 in the following example).
s := StructName{}
p2 := &s
I have an issue using this statement
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
This worked fine if I use the struct define inside the prog like
m.Post(Model, binding.Form(Wish1{}) , func(wish Wish1, r render.Render, db *mgo.Database) {
but I need this to be an independent package.
I get "Wish is not a type" wish is the return of the binding function.
This worked with a primary Type struct. I am passing the strut as a interface{}
I am using GO with Martini.Classic() It is really complicated for me to change Martini or Binding package. Any suggestions.
This is the all code
package chlistpkg
import (
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/binding"
"github.com/codegangsta/martini-contrib/render"
"labix.org/v2/mgo"
"time"
"fmt"
"html/template"
"reflect"
"adminStruct"
)
just to show the struct that I need to pass as to routine Doall
type Wish1 struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
DB Returns a martini.Handler
func DB() martini.Handler {
session, err := mgo.Dial("mongodb://localhost")
if err != nil {
panic(err)
}
return func(c martini.Context) {
s := session.Clone()
c.Map(s.DB("advent2"))
defer s.Close()
c.Next()
}
}
GetAll returns all Wishes in the database
func GetAll(db *mgo.Database, entList interface{}) interface{} {
db.C("wishes").Find(nil).All(entList)
fmt.Println("GettAll entList =", entList)
return entList
}
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
m.Use(render.Renderer(render.Options{
Directory: "templates",
Layout: "layout",
}))
m.Use(DB())
m.Get(Model, func(r render.Render, db *mgo.Database) {
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
binding does not take a pointer. I have to pass the struct by reference on "Wish"
the issue is the return on "wish Wish" I got an error Wish is not a type
at compilation time
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
fmt.Println("Input wish =", wish)
db.C("wishes").Insert(wish)
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
m.Run()
Thanks in advance
Luis
The reason you are getting an error is that you have called your type Wish1 (with a numerical 1) but you are referring to the Wish type (which does not exist!) in your code.
Change your struct to be:
// Note: "Wish", not "Wish1"
type Wish struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
If you want to put your type into another package (tip: don't overdo the sub-packages), then it will need to become a pkgname.Wish as names are fully qualified.
Added
After a second look, you're also messing things up here:
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
Your parameter list needs to provide a name for each type; you can't pass Wish interface{} as a parameter as Wish is a type, not a variable name.
You should either:
func DoAll(model string, wish interface{}, wish2 interface{}, wishList interface{}) { ... }
Or, better still, stop using interface{} like this and write:
func DoAll(model string, wishList []Wish, wishes... Wish) { ... }
However, your DoAll function does not seem to be referenced elsewhere, and is creating its own Martini instance. I highly suggest thinking about why things are "split out" like this if you're just starting out. Keep it simple - e.g.
func main() {
m := martini.Classic()
m.Use(martini.Static("images"))
m.Use(DB())
m.Use(render.Renderer(render.Options{...}))
// No need for an anonymous function, which just adds clutter
m.Get("/wishes/all", GetAllWishes)
// Same goes for here
m.Post("/wishes/new", PostWish)
m.Run()
}
PS: I've fixed the formatting of your code, as it has a lot of unnecessary spacing before/after parenthesis. Make sure to use gofmt, which is included with the Go install and can be hooked into most popular editors.