I have example play.golang.org/p/Y1KX-t5Sj9 where I define method Modify() on struct User
type User struct {
Name string
Age int
}
func (u *User) Modify() {
*u = User{Name: "Paul"}
}
in the main() I am defining struct literal &User{Name: "Leto", Age: 11} then call u.Modify(). That results in printing 'Paul 0' I like that struct field Name is changed , but what is the correct way to keep Age field ?
Just modify the field you want to change:
func (u *User) Modify() {
u.Name = "Paul"
}
This is covered well in the Go tour which you should definitely read through, it doesn't take long.
Related
I am trying to update "age" of data struct using SetAge() function after the array creation in the user struct. Here is the code snippet:
//data struct to set the user details
type data struct {
Name string `json:"name"`
College string `json:"college"`
Age int64 `json:"age"`
}
// user struct to store the user details in JSON Array
type user struct {
DataValue []*data `json:"data"`
}
func (u *user) Details(name, college string) *user {
d:=&data{Name:name, College:college}
u.DataValue=append(u.DataValue, d)
return u
}
func (u *user) SetAge(age int64) *user { //age is optional
// what code should be here such that age is added to resp detail
}
Output:
"data":[{
"name":"test",
"college":"test",
"age":10
},{
"name":"test",
"college":"test"
// in this object "Age" hasn't been set
}]
If you want to update the Age field of all the data objects, You're almost done.
You just need to iterate over the u.DataValue slice, and update the age field as follows:
func (u *user) SetAge(age int64) *user {
for index := range u.DataValue {
u.DataValue[index].Age = age
}
return u
}
As per the requirement in my application, it would be like this:
func (u *user) SetAge(age int64) *user {
u.DataValue[len(u.DataValue) - 1].Age = age
return u
}
I have some condition where to make a dynamic query, value is not set will be ignore. But I have confused how to determine the value is zero value is by input(user) or not (golang set for us)
example :
type User struct {
Age int
}
user := User{ Age : 0 } // query := `Where age = ... `
user := User{} // query := ``
I have use pointer and json before, it's work but in this case i cannot change the struct structure.
type User struct {
Age *int `json:"age"`
}
user :=User{}
if user.Age == nil { //not set }
is anyone can give me idea or keywords? Thanks
An alternative to map[string]interface may be to have a wrapping type (if possible in your case):
type UserWrapper {
user User
ageDirty bool
}
func (u UserWrapper) SetAge(age int) {
u.ageDirty = true
u.user.Age = age
}
func (u UserWrapper) GetAge() int {
return u.user.Age
}
func (u UserWrapper) AgeSet() bool {
return u.ageDirty
}
It makes the intentions clearer, even if it should be better to change the structure directly
I am new to go (golang). That is why my question may be irrelevant (or impossible to answer).
I have created two structs. Both of these embed another struct. Now I want to update a field of the embedded struct inside a function.
package main
import (
"fmt"
"reflect"
"time"
)
type Model struct {
UpdatedAt time.Time
}
type Fruit struct {
Model
label string
}
type Animal struct {
Model
label string
}
func update(v interface{}) {
reflectType := reflect.TypeOf(v)
reflectKind := reflectType.Kind()
if reflectKind == reflect.Ptr {
reflectType = reflectType.Elem()
}
m := reflect.Zero(reflectType)
fmt.Println(m)
}
func main() {
apple := &Fruit{
label: "Apple",
}
tiger := &Animal{
label: "Tiger",
}
update(apple)
update(tiger)
fmt.Println(apple)
fmt.Println(tiger)
}
I wish to implement the update function so that it will put the current time in UpdatedAt of the passed struct. But I am not able to do this.
In this case, the field of Fruit and Animal is same: label. But it will not always be. Please keep that in mind when providing your suggestions.
Any guidance would be much appreciated.
I'd avoid reflect or interface{} if you're starting to learn go. Beginners usually fall back on them like a void * crutch. Try to use concrete types or well defined interfaces.
This should get you going:
type Timestamper interface {
Update()
UpdatedTime() time.Time
}
type Model struct {
updated time.Time
}
func (m *Model) Update() { m.updated = time.Now() }
func (m *Model) UpdatedTime() time.Time { return m.updated }
type Fruit struct {
Model
label string
}
type Animal struct {
Model
label string
}
// update will work with a `Model` `Animal` or `Fruit`
// as they all implement the `Timestamper` interface`
func update(v Timestamper) {
v.Update()
}
Playground: https://play.golang.org/p/27yDVLr-zqd
Assuming you want to achieve this via reflection: first of all, you have to pass a pointer to the struct. You're now passing a copy of the struct, so any modifications done in update will be done on the copy, not on the instance you passed in. Then, you can lookup the field UpdatedAt in the interface passed in, and set it.
That said, that's probably not the best way to do this. Another way of doing this without reflection is:
func update(in *Model) {
in.UpdatedAt = time.Now()
}
func main() {
apple := &Fruit{}
update(&apple.Model)
}
Or:
func (in *Model) update() {
in.UpdatedAt = time.Now()
}
func main() {
apple := &Fruit{}
apple.update()
}
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 would like to create a base struct which have to method, I want to use these methods in the substructs. For example:
type Base struct {
Type string `json:"$type"`
}
func (b Base) GetJSON() ([]byte, error) {
return json.Marshal(b)
}
func (b Base) SetType(typeStr string) interface{} {
b.Type = typeStr
return b
}
In the new struct I want to use it like this:
type Auth struct {
Base
Username
Password
}
and call these methods in the main:
func main() {
a := Auth{
Username: "Test",
Password: "test",
}
a = a.SetType("testtype").(Auth)
j, _ := a.GetJSON()
}
In the SetType case I got a panic caused by interface{} is not Auth type, it is Base type.
In the GetJSON case I got a json about the Type, but only the Type.
Is there any solution for the problem what I want to solve?
As mentioned in the comments, embedding is not inheritance but composition, so you'll probably have to either:
Re-think your design to use the tools Go has available
Resort to extensive hacking to get the results you want
In the particular case you are showing (trying to get GetJSON() to include also the fields of the outer struct, here is a possible way of getting that to work that does not require many changes (just storing a pointer to the outer struct in Base when creating the struct):
package main
import (
"encoding/json"
"fmt"
)
type Base struct {
Type string `json:"$type"`
selfP interface{} // this will store a pointer to the actual sub struct
}
func (b *Base) SetSelfP(p interface{}) {
b.selfP = p
}
func (b *Base) GetJSON() ([]byte, error) {
return json.Marshal(b.selfP)
}
func (b *Base) SetType(typeStr string) {
b.Type = typeStr
}
type Auth struct {
Base
Username string
Password string
}
func main() {
a := &Auth{
Username: "Test",
Password: "test",
}
a.SetSelfP(a) // this line does the trick
a.SetType("testtype")
j, _ := a.GetJSON()
fmt.Println(string(j))
}
Playground link: https://play.golang.org/p/npuy6XMk_t