Automatic Type Assertion In Go - struct

Take this sample of code (playground):
package main
import (
"fmt"
)
type Foo struct {
Name string
}
var data = make(map[string]interface{})
func main() {
data["foo"] = &Foo{"John"}
foo := data["foo"].(*Foo)
fmt.Println(foo.Name)
}
When I add something to data, the type turns into an interface{}, so when I later retrieve that value I have to assert the original type back onto it. Is there a way to, for example, define a getter function for data which will automagically assert the type?

Not really, unless you turn to reflect and try to get the type of the interface that way.
But the idiomatic (and faster) way remains the type assertion (a "type conversion" which must be checked at runtime, since data only contains interface{} values).
If data were to reference a specific interface (instead of the generic interface{} one), like I mentioned here, then you could use a Name() method defined directly on it.

You can do something like this, but you might want to think about your design.. It is very rare that you need to do this kind of things.
http://play.golang.org/p/qPSxRoozaM
package main
import (
"fmt"
)
type GenericMap map[string]interface{}
func (gm GenericMap) GetString(key string) string {
return gm[key].(string)
}
func (gm GenericMap) GetFoo(key string) *Foo {
return gm[key].(*Foo)
}
func (gm GenericMap) GetInt(key string) int {
return gm[key].(int)
}
var data = make(GenericMap)
type Foo struct {
Name string
}
func main() {
data["foo"] = &Foo{"John"}
foo := data.GetFoo("foo")
fmt.Println(foo.Name)
}
You might want to add error checking, in case the key does not exists or is not the expected type.

Related

Is there a way to list methods of an object in GoLang? [duplicate]

The Golang "fmt" package has a dump method called Printf("%+v", anyStruct). I'm looking for any method to dump a struct and its methods too.
For example:
type Foo struct {
Prop string
}
func (f Foo)Bar() string {
return f.Prop
}
I want to check the existence of the Bar() method in an initialized instance of type Foo (not only properties).
Is there any good way to do this?
You can list the methods of a type using the reflect package. For example:
fooType := reflect.TypeOf(&Foo{})
for i := 0; i < fooType.NumMethod(); i++ {
method := fooType.Method(i)
fmt.Println(method.Name)
}
You can play around with this here: http://play.golang.org/p/wNuwVJM6vr
With that in mind, if you want to check whether a type implements a certain method set, you might find it easier to use interfaces and a type assertion. For instance:
func implementsBar(v interface{}) bool {
type Barer interface {
Bar() string
}
_, ok := v.(Barer)
return ok
}
...
fmt.Println("Foo implements the Bar method:", implementsBar(Foo{}))
Or if you just want what amounts to a compile time assertion that a particular type has the methods, you could simply include the following somewhere:
var _ Barer = Foo{}

Converting a custom type to string in Go

In this bizarre example, someone has created a new type which is really just a string:
type CustomType string
const (
Foobar CustomType = "somestring"
)
func SomeFunction() string {
return Foobar
}
However, this code fails to compile:
cannot use Foobar (type CustomType) as type string in return argument
How would you fix SomeFunction so that it is able to return the string value of Foobar ("somestring") ?
Convert the value to a string:
func SomeFunction() string {
return string(Foobar)
}
Better to define a String function for the Customtype - it can make your life easier over time - you have better control over things as and if the structure evolves. If you really need SomeFunction then let it return Foobar.String()
package main
import (
"fmt"
)
type CustomType string
const (
Foobar CustomType = "somestring"
)
func main() {
fmt.Println("Hello, playground", Foobar)
fmt.Printf("%s", Foobar)
fmt.Println("\n\n")
fmt.Println(SomeFunction())
}
func (c CustomType) String() string {
fmt.Println("Executing String() for CustomType!")
return string(c)
}
func SomeFunction() string {
return Foobar.String()
}
https://play.golang.org/p/jMKMcQjQj3
For every type T, there is a corresponding conversion operation T(x)
that converts the value x to type T. A conversion from one type to
another is allowed if both have the same underlying type, or if both
are unnamed pointer types that point to variables of the same
underlying type; these conversions change the type but not the
representation of the value. If x is assignable to T, a conversion
is permitted but is usually redundant. - Taken from The Go
Programming Language - by Alan A. A. Donovan
As per your example here are some of the different examples which will return the value.
package main
import "fmt"
type CustomType string
const (
Foobar CustomType = "somestring"
)
func SomeFunction() CustomType {
return Foobar
}
func SomeOtherFunction() string {
return string(Foobar)
}
func SomeOtherFunction2() CustomType {
return CustomType("somestring") // Here value is a static string.
}
func main() {
fmt.Println(SomeFunction())
fmt.Println(SomeOtherFunction())
fmt.Println(SomeOtherFunction2())
}
It will output:
somestring
somestring
somestring
The Go Playground link
You can convert like this:
var i int = 42
var f float64 = float64(i)
check here
you can return like this:
return string(Foobar)

Unexpected return of anonymous struct

I am trying to implement a method that returns a modified struct based on the original one, such as:
type Project struct {
Username string
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}
func (p *Project) OmitUsername() *struct {
return &struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}{
p.Id,
p.Alias,
p.Data,
p.Scheme
})
}
And I get the following error:
models/project.go:22: syntax error: unexpected return
models/project.go:24: non-declaration statement outside function body
models/project.go:25: non-declaration statement outside function body
models/project.go:25: syntax error: unexpected string literal, expecting semicolon or newline
models/project.go:26: non-declaration statement outside function body
Any help would be appreciated.
With "truly" anonymous struct return value
If you want to use an anonymous struct return value, that's gonna look really ugly.
Why? Because when you define the return type, you have to describe the anonymous struct. And when you write a return statement, you have to provide the return value which will be a struct literal. A struct literal for an anonymous struct also has to describe the struct!
When you attempt to write this:
func (p *Project) OmitUsername() *struct {
// return somethig
}
This syntax is not what you think: it doesn't contain the struct definition. Basically in your example the first { is the opening bracket of the anonymous struct definition, and not the opening bracket of the function body. And as such, the subsequent return is interpreted as being inside the anonymous struct definition which is invalid syntax, this is exactly what the error message states too ("syntax error: unexpected return").
It should look like this:
func (p *Project) OmitUsername() *struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
} {
// And now here comes the return statement
}
And if you also add the return statement which has to repeat the anonymous struct definition:
func (p *Project) OmitUsername() *struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
} {
return &struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}{p.Id, p.Alias, p.Data, p.Scheme}
}
Yes, it's ugly. You can make it a little simpler by using named return value, and not returning a pointer, because zero value of pointers is nil, and to return something, you'd have to initialize it which would also involve repeating the anonymous struct! If you use a non-pointer, named return value, you will have a value of the anonymous struct right away, and you don't have to repeat the anonymous struct definition again, just assign values to its fields:
func (p *Project) OmitUsername2() (ret struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}) {
ret.Id = p.Id
ret.Alias = p.Alias
ret.Data = p.Data
ret.Scheme = p.Scheme
return
}
Using them:
p := Project{"Bob", 1, "bobie", nil, nil}
fmt.Println(p.OmitUsername())
fmt.Println(p.OmitUsername2())
Output (try these on the Go Playground):
&{1 bobie <nil> <nil>}
{1 bobie <nil> <nil>}
Still ugly...
With another named type, using embedding
...Best would be to provide another named type to return and not an anonymous struct. You may utilize embedding to make this solution practical and short:
type BaseProject struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}
type Project struct {
BaseProject
Username string
}
func (p *Project) OmitUsername() BaseProject {
return p.BaseProject
}
Using it:
p := Project{BaseProject{1, "bobie", nil, nil}, "Bob"}
fmt.Println(p.OmitUsername())
Output (try this on the Go Playground):
{1 bobie <nil> <nil>}
Note:
Embedding is not really necessary, but this way the fields of the embedded type (BaseProject) will be promoted and so you can refer to them like p.Id as if they were defined in Project. Defining it as a regular field would also work.
The Go Programming Language Specification
Keywords
The following keywords are reserved and may not be used as identifiers.
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
.
func (p *Project) OmitUsername() *struct {
}
struct is a reserved keyword.
Without more information about what you are trying to do, it's hard to know what you want, pehaps something like this?
package main
import (
"encoding/json"
)
type Scheme struct{}
type Project struct {
Id uint
Alias string
Data *json.RawMessage
Scheme Scheme
}
type UserProject struct {
Username string
Project
}
func (u *UserProject) GetProject() *Project {
return &u.Project
}
func main() {}

Can you pass a struct fieldname in to a function in golang?

Say for example you have something like this, trying to make the example as simple as possible.
type Home struct {
Bedroom string
Bathroom string
}
How do you pass the field name, or can you, to a function?
func (this *Home) AddRoomName(fieldname, value string) {
this.fieldname = value
}
Obviously that does not work... The only way I can see to do this is to use two functions which adds a lot of extra code when the struct gets really big and has a lot of similar code.
func (this *Home) AddBedroomName(value string) {
this.Bedroom = value
}
func (this *Home) AddBathroomName(value string) {
this.Bathroom = value
}
The only way that I am aware of is to use reflection:
func (this *Home) AddRoomName(fieldname, value string) {
h := reflect.ValueOf(this).Elem()
h.FieldByName(fieldname).Set(reflect.ValueOf(value))
return
}
http://play.golang.org/p/ZvtF_05CE_
One more idea that comes to my mind is like this, not sure if it makes sense in your case though:
func Set(field *string, value string) {
*field = value
}
home := &Home{"asd", "zxc"}
fmt.Println(home)
Set(&home.Bedroom, "bedroom")
Set(&home.Bathroom, "bathroom")
fmt.Println(home)
http://play.golang.org/p/VGb69OLX-X
Use type assertions on an interface value:
package main
import "fmt"
type Test struct {
S string
I int
}
func (t *Test) setField(name string, value interface{}) {
switch name {
case "S":
t.S = value.(string)
case "I":
t.I = value.(int)
}
}
func main() {
t := &Test{"Hello", 0}
fmt.Println(t.S, t.I)
t.setField("S", "Goodbye")
t.setField("I", 1)
fmt.Println(t.S, t.I)
}

How to set and get fields in struct's method

After creating a struct like this:
type Foo struct {
name string
}
func (f Foo) SetName(name string) {
f.name = name
}
func (f Foo) GetName() string {
return f.name
}
How do I create a new instance of Foo and set and get the name?
I tried the following:
p := new(Foo)
p.SetName("Abc")
name := p.GetName()
fmt.Println(name)
Nothing gets printed, because name is empty. So how do I set and get a field inside a struct?
Working playground
Commentary (and working) example:
package main
import "fmt"
type Foo struct {
name string
}
// SetName receives a pointer to Foo so it can modify it.
func (f *Foo) SetName(name string) {
f.name = name
}
// Name receives a copy of Foo since it doesn't need to modify it.
func (f Foo) Name() string {
return f.name
}
func main() {
// Notice the Foo{}. The new(Foo) was just a syntactic sugar for &Foo{}
// and we don't need a pointer to the Foo, so I replaced it.
// Not relevant to the problem, though.
p := Foo{}
p.SetName("Abc")
name := p.Name()
fmt.Println(name)
}
Test it and take A Tour of Go to learn more about methods and pointers, and the basics of Go at all.
Setters and getters are not that idiomatic to Go.
Especially the getter for a field x is not named GetX
but just X.
See http://golang.org/doc/effective_go.html#Getters
If the setter does not provide special logic, e.g.
validation logic, there is nothing wrong with exporting
the field and neither providing a setter nor a getter
method. (This just feels wrong for someone with a
Java background. But it is not.)
For example,
package main
import "fmt"
type Foo struct {
name string
}
func (f *Foo) SetName(name string) {
f.name = name
}
func (f *Foo) Name() string {
return f.name
}
func main() {
p := new(Foo)
p.SetName("Abc")
name := p.Name()
fmt.Println(name)
}
Output:
Abc

Resources