Home  >  Article  >  Backend Development  >  Override structure fields with values ​​from other "part" structures

Override structure fields with values ​​from other "part" structures

WBOY
WBOYforward
2024-02-12 18:30:09919browse

Override structure fields with values ​​from other part structures

php editor Xigua is here to introduce to you a method about using values ​​in other "part" structures to overwrite structure fields. In programming, we often need to update the values ​​of structure fields according to different situations. In this case, we can overwrite the fields in the target structure with values ​​from other structures. This method is very practical and can improve the readability and flexibility of the code. Next, I'll detail how to use this technique to simplify your code and make it more efficient.

Question content

I am new to Go and trying to create a CRUD API. Please forgive me that the OOP approach in Go may not be smart. I have a structure that I want to partially update via the PATCH endpoint.

type Book struct {
  Id        uuid.UUID  `json:"id"`
  Author    uuid.UUID  `json:"author"`
  Title     string     `json:"title"`
  IsPublic  bool       `json:"isPublic"`
  CreatedAt time.Time  `json:"createdAt"`
  UpdatedAt *time.Time `json:"updatedAt"`
  DeletedAt *time.Time `json:"deletedAt"`
}

I have defined a second structure that contains an updateable property for a book.

type PatchBookDto struct {
  Author   *uuid.UUID
  Title    *string
  IsPublic *bool
}

In both structures, I'm using (possibly abusing?) pointer attributes to simulate optional parameters. What I want to achieve is to overwrite a book with any given property in PatchBookDto. Here's what I've tried so far:

var book models.Book // Is taken from an array of books
var dto dtos.PatchBookDto

if err := c.BindJSON(&dto); err != nil {
    // Abort
}

dtoTypeInfo := reflect.TypeOf(&dto).Elem()

for i := 0; i < dtoTypeInfo.NumField(); i++ {
    dtoField := dtoTypeInfo.Field(i)
    bookField := reflect.ValueOf(&book).Elem().FieldByName(dtoField.Name)

    if bookField.IsValid() && bookField.CanSet() {

        dtoValue := reflect.ValueOf(dto).Field(i)

        if dtoValue.Interface() == reflect.Zero(dtoValue.Type()).Interface() {
            continue
        }

        if dtoField.Type.Kind() == reflect.Ptr {
            if dtoValue.Elem().Type().AssignableTo(bookField.Type()) {
                bookField.Set(dtoValue.Elem())
            } else {
                // Abort
            }
        }

        convertedValue := dtoValue.Convert(bookField.Type())
        bookField.Set(convertedValue)
    }
}

When I test this, I get the reflect.Value.Convert: value of type *string Cannot be converted to type string error.

Does anyone know what I can improve here to get what I need?

Workaround

Looks like you intended to put the panic line in the else block of if dtoField.Type.Kind() ==reflect.Ptr.

Another way is to use an indirect pointer and then set the value.

for i := 0; i < dtoTypeInfo.NumField(); i++ {
    dtoField := dtoTypeInfo.Field(i)
    bookField := reflect.ValueOf(&book).Elem().FieldByName(dtoField.Name)
    if bookField.IsValid() && bookField.CanSet() {
        dtoValue := reflect.ValueOf(dto).Field(i)
        if dtoValue.Interface() == reflect.Zero(dtoValue.Type()).Interface() {
            continue
        }
        dtoValue = reflect.Indirect(dtoValue)
        convertedValue := dtoValue.Convert(bookField.Type())
        bookField.Set(convertedValue)
    }
}

The above is the detailed content of Override structure fields with values ​​from other "part" structures. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete