Как динамически заполнять структуру данными?

В моем сервисе gRPC, который был написан на golang, у меня есть такой rpc method с именем CreateCity. Как видите, в этом методе я хочу создать новую запись в базе данных и вернуть всю информацию об этой записи в качестве ответа.

func (server *Server) CreateCity(context context.Context, request *proto.CreateCityRequest) (*proto.CreateCityResponse, error) {
    city := proto.City {
        Name: request.GetCity().Name,
        Country: request.GetCity().Country,
    }

    err := databases.DBGORM.Table("city").Create(&city).Error
    if err != nil {
        utils.Logger().Println(err.Error())
        return nil, status.Errorf(codes.Internal, err.Error())
    }

    result := &proto.CreateCityResponse {
        City: &city,
    }

    return result, nil
}

Файл proto выглядит так:

syntax = "proto3";

package proto;

import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

option go_package = "./proto";

service CityService {
    rpc CreateCity(CreateCityRequest) returns (CreateCityResponse) {}
}

message City {
    google.protobuf.StringValue name = 1 [json_name = "name", (gogoproto.jsontag) = "name", (gogoproto.wktpointer) = true];
    google.protobuf.StringValue country = 2 [json_name = "country", (gogoproto.jsontag) = "country", (gogoproto.wktpointer) = true];
}

message CreateDealerGroupRequest {
    City city = 1;
}

message CreateDealerGroupResponse {
    City city = 1;
}

Можно ли динамически заполнять структуру данными без явного указания имени? Как видите, я явно указываю имя полей и их значение:

city := proto.City {
    Name: request.GetCity().Name,
    Country: request.GetCity().Country,
}

person Nurzhan Nogerbek    schedule 17.05.2020    source источник
comment
Отвечает ли это на ваш вопрос? Скопируйте одну структуру в другую, где структуры имеют одинаковые члены и разные типы   -  person Eklavya    schedule 17.05.2020


Ответы (2)


Вы можете использовать json.Marshal создать массив байтов json, а затем json.Unmarshal

inrec, _ := json.Marshal(request.GetCity())
json.Unmarshal(inrec, &city)
person Kmarlon Pereira    schedule 17.05.2020

Я считаю, что лучше всего сделать то, что вы хотите, - это использовать отражение и пройти через все поля исходной структуры, сравнить их с целевой структурой и назначить их, если они совпадают.

Быстрый поиск в Google обнаружил этот пакет: https://github.com/stroiman/go-automapper. (Я сам не использовал его, просто поместил его здесь в качестве примера)
Код, который вам нужен, находится здесь:
здесь.
Не хочу включать код в этот ответ, так как вы, возможно, захотите его изменить, но общая идея есть.

Лично я бы выбрал ручной подход (как вы делаете сейчас), если это вообще возможно. Полагаться на отражение будет медленнее, но, возможно, что более важно, изменения модели могут непредвиденным образом повлиять на отображение. Просто зависит от вашего варианта использования imo.

person erikbozic    schedule 17.05.2020