Я относительно новичок в Go и работаю над созданием декодера запросов. Запрос приходит в формате JSON, и мы декодируем его в интерфейс map[string]{}. Затем мы передаем эти данные объекта для декодирования в нашу собственную структуру ProcessRequest. Как я уже сказал, я новичок, поэтому повторно использую некоторую логику в аналогичных частях кода, написанных предыдущими разработчиками. По сути, мы проверяем карту на наличие необходимых фрагментов, а затем устанавливаем и возвращаем их. Может ли кто-нибудь объяснить мне, почему я получаю заголовочную ошибку? Должен ли я устанавливать элементы вплоть до базовых структур, которые больше не имеют вложенности? Есть ли лучший способ выполнить то, что я хочу? Вот код и связанные структуры. Он выделяет ошибку при возврате model.ProcessRequest. ТИА
type ProcessRequest struct {
RequestID string
Message *message.Message
Rule *Rule
Options *ProcessOptions
//TODO: Context EvaluatorContext
//TODO: Links
}
type Message struct {
ID int
Key string
Source string
Headers *HeaderSet
Categories *CategorySet
Properties *PropertySet
Streams *StreamSet
}
type RuleAction struct {
Name string
Expression map[string]interface{}
}
type RuleLink struct {
LinkID int
Condition map[string]interface{}
TargetRuleID int
}
type Rule struct {
Name string
Code string
Actions []RuleAction
Links []RuleLink
}
type object = map[string]interface{}
func DecodeProcessRequest(dataObject map[string]interface{}) (*model.ProcessRequest, error) {
var (
requestID string
message *message.Message
rule *model.Rule
options *model.ProcessOptions
err error
)
if reqIDSrc, ok := dataObject["requestId"]; ok {
if requestID, err = converter.ToString(reqIDSrc); err != nil {
return nil, errors.Wrapf(err, "Error reading property 'requestID'")
}
if requestID == "" {
return nil, errors.Errorf("Property 'requestID' is an empty string")
}
} else {
return nil, errors.Errorf("Missing required property 'requestID'")
}
if messageSrc, ok := dataObject["message"]; ok {
messageData, ok := messageSrc.(object)
if !ok {
return nil, errors.Errorf("Error reading property 'message': Value is not an object")
}
if message, err = DecodeMessage(messageData); err != nil {
return nil, errors.Wrapf(err, "Error reading property 'message'")
}
} else {
return nil, errors.Errorf("Missing required property 'message'")
}
if ruleSrc, ok := dataObject["rule"]; ok {
ruleObj, ok := ruleSrc.(object)
if !ok {
return nil, errors.Errorf("Error reading property 'rule': Value is not an object")
}
if rule, err = DecodeRule(ruleObj); err != nil {
return nil, errors.Wrapf(err, "Error reading 'rule' during decoding")
}
} else {
return nil, errors.Errorf("Missing required property 'requestID'")
}
// Parse plain object to a Message struct
return &model.ProcessRequest{
requestID,
message,
rule,
options,
}, nil
}
В общем, в предупреждении говорится, что лучше использовать синтаксис ProcessRequest{ RequestID: requestID, ... }
. Именование ключей вместо неключевых значений.
Некоторые из значений struct
s, которые вы пытаетесь построить с помощью составной литерал, содержат поле с именем _
(единственное подчеркивание). Это заставляет компилятор отклонить определение, если только вы не используете нотацию FieldName: fieldValue
для установки значений полей. Это своего рода хак, предназначенный для того, чтобы сделать такие литералы устойчивыми к изменениям порядка полей в определении таких struct
типов.
Спасибо, что добавили в RequestID: requestID устранил ошибку. Я не могу пометить это как ответ по какой-то причине?
В основном идея состоит в том, что если вы используете «неключевой» способ определения литералов структуры, значение ваших определений зависит от того, как расположены поля базового типа. Теперь учтите, что ваш тип имеет три поля типа string
в определенном порядке. Теперь через пару итераций какой-нибудь программист переместит второе поле на 1-ю позицию — ваш литерал все еще будет компилироваться, но в конечном итоге во время выполнения будет определено совершенно другое значение.
супер сказал в этот комментарий:
In general, the warning says that you should prefer to use the syntax
ProcessRequest{ RequestID: requestID, ... }
. Naming the keys instead of unkeyed values.
Это сработало для меня. Также очень помогло объяснение костикс в этот комментарий.
Basically the idea is that if you use "unkeyed" way of defining struct literals, the meaning of your definitions depends on the way the fields of the underlying type are layed out. Now consider that your type has three fields of type
string
in a certain order. Now a couple of iterations down the road some programmer moves the second field to the 1st position—your literal will still compile but will end up defining a completely different value at runtime.
Пожалуйста, включите сообщение об ошибке в вопрос и покажите, какая часть кода вызывает ошибку. Также всегда полезно удалить как можно больше кода. Сохраняйте ровно столько кода, сколько необходимо для воспроизведения ошибки. Посмотрите, как сделать минимальный воспроизводимый пример.