I have this struct call Status and have inside another struct call Data
package model
import "time"
type Status struct {
Data struct {
OrderId string json:"orderId"
DisputeStatus string json:"disputeStatus"
DisputeCauseCategoryName string json:"disputeCauseCategoryName"
ReverseLogisticCost string json:"ReverseLogisticCost"
} json:"data"
StatusJ string json:"status"
}
And i have this function
func (s StatusServices) UpdateStatusItem(ctx context.Context, status model.Status) (error) {
statusDetails := model.Status{
OrderID: status.Data.OrderID,
}
}
In OrderId appear the error Invalid field name, i tried with this
statusDetails := model.Status{
Data: status.Data{
OrderID: status.Data.OrderID,
},
}
but i doesn't work, what can i do
The type model.Status has a field Data with a type defined as
struct {
OrderId string json:"orderId"
DisputeStatus string json:"disputeStatus"
DisputeCauseCategoryName string json:"disputeCauseCategoryName"
ReverseLogisticCost string json:"ReverseLogisticCost"
}
To initialize the variable, you can use a composite literal, more specifically a struct literal
func main() {
s := Status{
Data: struct {
OrderId string `json:"orderId"`
DisputeStatus string `json:"disputeStatus"`
DisputeCauseCategoryName string `json:"disputeCauseCategoryName"`
ReverseLogisticCost string `json:"ReverseLogisticCost"`
}{OrderId: "123456"},
}
fmt.Println(s)
}
https://play.golang.org/p/nLhLHNNf7Jb
I do not believe you can initialize a struct with a nested struct this way.
Best is to give the nested struct its own type. OR you can start with an empty struct (eg var m model.Status) and then (in a separate line) assign to s.Data.OrderId.
I believe you can only assign to a nested struct if you define and initialize it in one go (as is often done in go tests) which is consistent with the idea that this construct is useful only for onetime off uses.
Not sure it answers your question, but you may want to modify your model a little bit from :
type Status struct {
Data struct {
OrderId string json:"orderId"
DisputeStatus string json:"disputeStatus"
DisputeCauseCategoryName string json:"disputeCauseCategoryName"
ReverseLogisticCost string json:"ReverseLogisticCost"
} json:"data"
StatusJ string json:"status"
}
To:
type Status struct {
Data Data `json:"data"`
StatusJ string `json:"status"`
}
type Data struct {
OrderID string `json:"orderId"`
DisputeStatus string `json:"disputeStatus"`
DisputeCauseCategoryName string `json:"disputeCauseCategoryName"`
ReverseLogisticCost string `json:"reverseLogisticCost"`
}
Check the capital letter; in your example you had OrderId in your Data struct but status.Data.OrderID in your function.
Also your field Status does not contain an OrderID field which you were setting in your function.
As mentionned in comment, backticks were missing around your json tags.
A proper IDE would catch those.
Change OrderID to OrderId,declare the field's type upfront as per suggestion of mkopriva:
package main
import (
"fmt"
)
type StatusData struct {
OrderId string `json:"orderId"`
DisputeStatus string `json:"disputeStatus"`
DisputeCauseCategoryName string `json:"disputeCauseCategoryName"`
ReverseLogisticCost string `json:"ReverseLogisticCost"`
}
type Status struct {
Data StatusData
StatusJ string
}
func main() {
s := Status{Data: StatusData{OrderId: "123456"}}
fmt.Println(s)
}
Output:
{{123456 } }
Related
I have a struct definition
type ds struct {
name string
TagList []struct {
Key string `json:"Key"`
Value string `json:"Value"`
} `json:"TagList"`
}
I want to have a function that converts the TagList into string arrays (my own serialization function). So the function will look like this
func serialize(tagList <?>) string
What I should define as the type <?> is what I am not sure about. Because if I called this function using
serialize(mydata.TagList) // mydata is the ds struct type
Then it will remind me that this type is []struct{...}
But I am not sure how to define the []struct{...}.
I am also open for existing serialization library apis i can use to do this as long as it serialized into a string.
The recommended approach is to declare a new type for the nested struct field so that you can reference the type by name whenever you need to; for example:
type Tag struct {
Key string `json:"Key"`
Value string `json:"Value"`
}
type ds struct {
name string
TagList []Tag `json:"TagList"`
}
// ...
func serialize(tagList []Tag) string {
// ...
}
Otherwise, without declaring the new type, one would have to repeat the whole type definition of the anonymous struct in every place where one wants to use that type; for example:
func serialize(tagList []struct {
Key string `json:"Key"`
Value string `json:"Value"`
}) string {
// ...
}
I need to get a type based on a string key of types map. Suppose I have the following types:
type RequestType struct {
Type string `json:"type"`
//Params map[string]string `json:"params"`//include params here? Contents of Params may be different among requests
}
type ParamsRequest struct {
RequestType
Param1 string
Param2 string
}
type OtherRequest struct {
RequestType
Param3 string
Param4 string
}
Later on..
var requestTypes = map[string]protocol.RequestType{
"base": ParamsRequest{}, //error here (Cannot use ParamsRequest as the type RequestType)
"base2": OtherRequest{},
}
params := requestTypes["base"] //or base2
And in the code I need to access common fields for all request types:
myFunction(params.Type)//or params.Params
Or params, specific for concrete type.
So:
params := requestTypes["base"]
fmt.Println(params.Type)//common for everyone
fmt.Println(params.Param1)
fmt.Println(params.Param2)
Or:
params := requestTypes["base2"]
fmt.Println(params.Type)
fmt.Println(params.Param3)
fmt.Println(params.Param4)
Or:
params := requestTypes["base"]
fmt.Println(params.Params.Param1)
fmt.Println(params.Params.Param2)
But instead when declaring my map I get the following error:
Cannot use ParamsRequest as the type RequestType
Any idea would be welcome. Thank you.
If I understand the requirement correctly here, you want to create an interface of RequestType which will be implemented by both the Request structs. below is a sample code for it.
package main
import "fmt"
type RequestType interface {
Type() string // an interface with Type as a function
}
type ParamsRequest struct {
Param1 string
Param2 string
}
func (p ParamsRequest) Type() string { // different Type() logic for different Request types
return fmt.Sprintf("%s,%s", p.Param1, p.Param2)
}
type OtherRequest struct {
Param3 string
Param4 string
}
func (o OtherRequest) Type() string {
return fmt.Sprintf("%s,%s", o.Param3, o.Param4)
}
func main() {
var requestTypes = map[string]RequestType{
"base": ParamsRequest{Param1: "hi", Param2: "bye"}, //error here (Cannot use ParamsRequest as the type RequestType)
"base2": OtherRequest{},
}
myFunction(requestTypes["base"].Type())
}
func myFunction(paramTypeString string) {
fmt.Printf("%s\ndont know ...\n", paramTypeString)
}
type TestObject struct {
kind string `json:"kind"`
id string `json:"id, omitempty"`
name string `json:"name"`
email string `json:"email"`
}
func TestCreateSingleItemResponse(t *testing.T) {
testObject := new(TestObject)
testObject.kind = "TestObject"
testObject.id = "f73h5jf8"
testObject.name = "Yuri Gagarin"
testObject.email = "Yuri.Gagarin#Vostok.com"
fmt.Println(testObject)
b, err := json.Marshal(testObject)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(b[:]))
}
Here is the output:
[ `go test -test.run="^TestCreateSingleItemResponse$"` | done: 2.195666095s ]
{TestObject f73h5jf8 Yuri Gagarin Yuri.Gagarin#Vostok.com}
{}
PASS
Why is the JSON essentially empty?
You need to export the fields in TestObject by capitalizing the first letter in the field name. Change kind to Kind and so on.
type TestObject struct {
Kind string `json:"kind"`
Id string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
}
The encoding/json package and similar packages ignore unexported fields.
The `json:"..."` strings that follow the field declarations are struct tags. The tags in this struct set the names of the struct's fields when marshaling to and from JSON.
Ru it on the playground.
When the first letter is capitalised, the identifier is public to any
piece of code that you want to use.
When the first letter is lowercase, the identifier is private and
could only be accessed within the package it was declared.
Examples
var aName // private
var BigBro // public (exported)
var 123abc // illegal
func (p *Person) SetEmail(email string) { // public because SetEmail() function starts with upper case
p.email = email
}
func (p Person) email() string { // private because email() function starts with lower case
return p.email
}
In golang
in struct first letter must uppercase
ex. phonenumber -> PhoneNumber
======= Add detail
First, I'm try coding like this
type Questions struct {
id string
questionDesc string
questionID string
ans string
choices struct {
choice1 string
choice2 string
choice3 string
choice4 string
}
}
golang compile is not error and not show warning. But response is empty because something
After that, I search google found this article
Struct Types and Struct Type Literals
Article then... I try edit code.
//Questions map field name like database
type Questions struct {
ID string
QuestionDesc string
QuestionID string
Ans string
Choices struct {
Choice1 string
Choice2 string
Choice3 string
Choice4 string
}
}
Is work.
Hope for help.
Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.
I have two struct having the same members, I want to copy one struct to another, see the pseudo code below:
type Common struct {
Gender int
From string
To string
}
type Foo struct {
Id string
Name string
Extra Common
}
type Bar struct {
Id string
Name string
Extra Common
}
Then I have foo of struct Foo, and bar of struct Bar, Is there any way to copy bar from foo?
Use a conversion to change the type. The following code uses a conversion to copy a value of type Foo to a value of type Bar:
foo := Foo{Id: "123", Name: "Joe"}
bar := Bar(foo)
playground example
The conversion only works when the underlying types are identical except for struct tags.
https://github.com/jinzhu/copier (same author of gorm) is also quite a good one, I have nested structs and all I do is:
copier.Copy(&employees, &user)
works great
If you would like to copy or clone to a different struct, I would suggest using deepcopier
It provides nice features like skipping, custom mapping, and forcing. below is an example from github:
Install:
go get -u github.com/ulule/deepcopier
Example:
package main
import (
"fmt"
"github.com/ulule/deepcopier"
)
// Model
type User struct {
// Basic string field
Name string
// Deepcopier supports https://golang.org/pkg/database/sql/driver/#Valuer
Email sql.NullString
}
func (u *User) MethodThatTakesContext(ctx map[string]interface{}) string {
// do whatever you want
return "hello from this method"
}
// Resource
type UserResource struct {
//copy from field "Name"
DisplayName string `deepcopier:"field:Name"`
//this will be skipped in copy
SkipMe string `deepcopier:"skip"`
//this should call method named MethodThatTakesContext
MethodThatTakesContext string `deepcopier:"context"`
Email string `deepcopier:"force"`
}
func main() {
user := &User{
Name: "gilles",
Email: sql.NullString{
Valid: true,
String: "gilles#example.com",
},
}
resource := &UserResource{}
deepcopier.Copy(user).To(resource)
//copied from User's Name field
fmt.Println(resource.DisplayName)//output: gilles
fmt.Println(resource.Email) //output: gilles#example.com
fmt.Println(resource.MethodThatTakesContext) //output: hello from this method
}
Also, some other way you could achieve this is by encoding the source object to JSON and then decode it back to the destination object.
This is another possible answer
type Common struct {
Gender int
From string
To string
}
type Foo struct {
Id string
Name string
Extra Common
}
type Bar struct {
Id string
Name string
Extra Common
}
foo:=Foo{
Id:"123",
Name:"damitha",
Extra: struct {
Gender int
From string
To string
}{Gender:1 , From:"xx", To:"yy" },
}
bar:=*(*Bar)(unsafe.Pointer(&foo))
fmt.Printf("%+v\n",bar)
If you would like to copy or clone to a different struct, I would suggest using deepcopier
It provides nice features like skipping, custom mapping, and forcing.
You can achieve nested struct copy following way.
Install:
go get -u github.com/ulule/deepcopier
Example:
package main
import (
"fmt"
"strconv"
"github.com/ulule/deepcopier"
)
//FieldStruct - Field Struct
type FieldStruct struct {
Name string `deepcopier:"field:TargetName"`
Type string `deepcopier:"field:TargetType"`
}
//SourceStruct - Source Struct
type SourceStruct struct {
Name string `deepcopier:"field:TargetName"`
Age int `deepcopier:"field:TargetAge"`
StringArray []string `deepcopier:"field:TargetStringArray"`
StringToInt string `deepcopier:"context"`
Field FieldStruct
Fields []FieldStruct
}
//TargetFieldStruct - Field Struct
type TargetFieldStruct struct {
TargetName string
TargetType string
}
//TargetStruct - Target Struct
type TargetStruct struct {
TargetName string
TargetAge int
TargetStringArray []string
TargetInt int
TargetField TargetFieldStruct
TargetFields []TargetFieldStruct
}
//write methods
//TargetInt - StringToInt
func (s *SourceStruct) TargetInt() int {
i, _ := strconv.Atoi(s.StringToInt)
return i
}
func main() {
s := &SourceStruct{
Name: "Name",
Age: 12,
StringArray: []string{"1", "2"},
StringToInt: "123",
Field: FieldStruct{
Name: "Field",
Type: "String",
},
Fields: []FieldStruct{
FieldStruct{
Name: "Field1",
Type: "String1",
},
FieldStruct{
Name: "Field2",
Type: "String2",
},
},
}
t := &TargetStruct{}
//coping data into inner struct
deepcopier.Copy(&t.TargetField).From(&s.Field)
// copied array of Struct
for i := range s.Fields {
// init a struct
t.TargetFields = append(t.TargetFields, TargetFieldStruct{})
// coping the data
deepcopier.Copy(&t.TargetFields[i]).From(&s.Fields[i])
}
//Top level copy
deepcopier.Copy(t).From(s)
fmt.Println(t)
}
Output:
&{Name 12 [1 2] 123 {Field String} [{Field1 String1} {Field2 String2}]}