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() {}
Related
What I want to do is:
1. Parse model from url parameter in endpoint.(ex: media, account)
mysite.com/v1/rest/:model <- :model can be whether 'media', 'account'.
So it will look like:
mysite.com/v1/rest/media
mysite.com/v1/rest/account
2. Use 1, retrieve string and use it for getting corresponding struct.
3. Put it to the method which takes interface{}
My code looks like:
type Media struct {
Caption string
}
type Account struct {
Bio string
}
type AdminController struct {
TableName string
ID int64
}
func (c *AdminController) Get(n *core.Network) {
// I want to put struct to below GetModels method dynamically.
// Not explicitly like this.
total, data, err := c.GetModels(&Media{}, n)
// I want to do this
total, data, err := c.GetModels(caster("media"), n)
if err != nil {
n.Res.Error(err)
} else {
n.Res.Success(total, data)
}
}
Is it possible to implement method which takes string and return corresponding struct? Like this:
func (c *AdminController) caster(model string) interface{} {
if string == "media" {
return &Media{}
} else if string == "account" {
return &Account{}
}
return nil
}
If it's possible, is this a good way to deal with REST request (generic way) Or should I implement response methods one by one following table by table?
If I have to implement REST(4) * number_of_tables methods, it doesn't seem to be efficient. Any advice on this architectural problem will be appreciated.
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)
}
This question already has answers here:
How to initialize a nested struct?
(10 answers)
Closed 7 years ago.
Hi I am very new to Golang, please help me. I have defined a struct inside a struct. But I get an error when I try to initialise the main struct.
type DetailsFilter struct {
Filter struct {
Name string
ID int
}
}
var M map[string]interface{}
M = make(map[string]interface{})
M["Filter"] = map[string]interface{}{"Name": "XYZ", "ID": 5}
var detailsFilter = DetailsFilter{Filter: M["Filter"]}}
The error I get is : can not use (type interface {}) as type struct in field value : need type assertion.
Please suggest a way to initialise DetailsFilter.
I tried doing the method described in Initialize a nested struct in Golang, but even this is not working.
Unfortunately if the type of a struct field is an anonymous struct, at construction time you can only initialize it by "duplicating" the anonymous struct type (specifying it again):
type DetailsFilter struct {
Filter struct {
Name string
ID int
}
}
df := DetailsFilter{Filter: struct {
Name string
ID int
}{Name: "myname", ID: 123}}
fmt.Println(df)
Output:
{Filter:{Name:myname ID:123}}
Shorter Alternative
So instead I recommend not to initialize it at construction, but rather after the zero-valued struct has been created, like this:
df = DetailsFilter{}
df.Filter.Name = "myname2"
df.Filter.ID = 321
fmt.Printf("%+v\n", df)
Output:
{Filter:{Name:myname2 ID:321}}
Try it on the Go Playground.
Naming the anonymous struct type
Or don't use anonymous struct as field type at all, name the type like this:
type Filter struct {
Name string
ID int
}
type DetailsFilter struct {
Filter Filter
}
And then you can simply initialize it like this:
df := DetailsFilter{Filter: Filter{Name: "myname", ID: 123}}
fmt.Printf("%+v\n", df)
Output (try it on the Go Playground):
{Filter:{Name:myname ID:123}}
The type of M["Filter"] to the compiler is interface{}. The type to the runtime is map[string]interface{}. Neither of those is convertable to your anonymous struct type for the Filter field.
You should define a type for filter, or just not have it at all. Why not
type DetailsFilter struct {
Name string
ID int
}
M := make(map[string]*DetailsFilter)
M["Filter"] = &DetailsFilter{"Name": "XYZ", "ID": 5}
var detailsFilter = M["Filter"]
I am not sure why you need the nested anonymous struct at all. In general it is not needed to use interface{} unless you really need to. It is usually a sign you are fighting the type system instead of embracing it.
The reason You should not use an anonymous struct like that is that there is no clean way to intialize it. You have two options:
1- Repeat the type definition in the struct literal:
x := DetailsFilter{Filter: struct {
Name string
ID int
}{Name: "Foo", ID: 5}}
2- Set individual fields:
x := DetailsFilter{}
x.Filter.Name = "Foo"
x.Filter.ID = 5
It seems easier to create a real type for the nested field if you want to create them with struct literals.
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.
Let's say I have two similar types set this way :
type type1 []struct {
Field1 string
Field2 int
}
type type2 []struct {
Field1 string
Field2 int
}
Is there a direct way to write values from a type1 to a type2, knowing that they have the same fields ?
(other than writing a loop that will copy all the fields from the source to the target)
Thanks.
To give a reference to OneOfOne's answer, see the Conversions section of the spec.
It states that
A non-constant value x can be converted to type T in any of these
cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or a slice of bytes or runes and T is a string type.
x is a string and T is a slice of bytes or runes.
The first and highlighted case is your case. Both types have the underlying type
[]struct { Field1 string Field2 int }
An underlying type is defined as
If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration. (spec, Types)
You are using a type literal to define your type so this type literal is your underlying type.
For your specific example, you can easily convert it playground:
t1 := type1{{"A", 1}, {"B", 2}}
t2 := type2(t1)
fmt.Println(t2)
As of Go 1.8, struct tags are ignored when converting a value from one struct type to another. Types type1 and type2 will be convertible, regardless of their struct tags, in that Go release. https://beta.golang.org/doc/go1.8#language
Nicolas, in your later comment you said you were using field tags on the struct; these count as part of definition, so t1 and t2 as defined below are different and you cannot cast t2(t1):
type t1 struct {
Field1 string
}
type t2 struct {
Field1 string `json:"field_1"`
}
UPDATE: This is no longer true as of Go 1.8
This is not the standard way, but if you wish to have a flexible approach to convert a struct to, lets say, a map, or if you want to get rid of some properties of your struct without using `json:"-", you can use JSON marshal.
Concretely, here is what I do:
type originalStruct []struct {
Field1 string
Field2 int
}
targetStruct := make(map[string]interface{}) // `targetStruct` can be anything of your choice
temporaryVariable, _ := json.Marshal(originalStruct)
err = json.Unmarshal(temporaryVariable, &targetStruct)
if err != nil {
// Catch the exception to handle it as per your need
}
Might seem like a hack, but was pretty useful in most of my tasks.
for go v1.18 that already support generic, basically i just create method that accept any type of parameter and convert it to another type with json.Marshal / Unmarshal
// utils.TypeConverter
func TypeConverter[R any](data any) (*R, error) {
var result R
b, err := json.Marshal(&data)
if err != nil {
return nil, err
}
err = json.Unmarshal(b, &result)
if err != nil {
return nil, err
}
return &result, err
}
suppose that i have a struct called models.CreateUserRequest and i want to convert it to models.User. Note that json tag must be same
// models.CreateUserRequest
type CreateUserRequest struct {
Fullname string `json:"name,omitempty"`
RegisterEmail string `json:"email,omitempty"`
}
// models.User
type User struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
}
I can use that utils method above like this
user := models.CreateUserRequest {
Name: "John Doe",
Email: "johndoe#gmail.com"
}
data, err := utils.TypeConverter[models.User](&user)
if err != nil {
log.Println(err.Error())
}
log.Println(reflrect.TypeOf(data)) // will output *models.User
log.Println(data)
You can manually use a mapper function which maps each element of type t1 to type t2. It will work.
func GetT2FromT1(ob1 *t1) *t2 {
ob2 := &t2 { Field1: t1.Field1, }
return ob2
}
Agniswar Bakshi's answer is faster and better if you can write those conversions manually, but here's an expansion on Furqan Rahamath's answer. (A more complete example is available on the Golang playground )
func Recast(a, b interface{}) error {
js, err := json.Marshal(a)
if err != nil {
return err
}
return json.Unmarshal(js, b)
}
// Usage:
type User struct {
Name string
PasswordHash string
}
// remove PasswordHash before providing user:
type PrivateOutgoingUser struct {
Name string
}
u1 := &User{Name: "Alice", PasswordHash: "argon2...."}
u2 := &PrivateOutgoingUser{}
err = Recast(u1, u2)
if err != nil {
log.Panic("Error recasting u1 to u2", err)
}
log.Println("Limited user:", u2)
Here's another way that uses JSON tagging which is faster, since it doesn't require that extra marshal-unmarshal step, but not quite as flexible:
type User struct {
Name string
PasswordHash string `json:"-"` // - removes the field with JSON
}
user := &User{Name: "Tommy Tester", PasswordHash: "argon2...."}
js, err := json.Marshal(user)
log.Println("Limited user:", string(user))