0
type Alpha struct { 
  Name            string `json:"name"`
  SkipWhenMarshal string `json:"skipWhenMarshal"`
}

func MarshalJSON(out interface{}){
  json.Marshal(out)
} 

Is it possible to ignore the SkipWhenMarshal field when I do json.Marshal but not when I do json.Unmarshal. It should work for any type who calls MarshalJSON

4

4 回答 4

3

“omitempty”和“-”之类的字段标记修饰符适用于编组和解组,因此没有自动方式。

您可以MarshalJSON为您的类型实现一个忽略您需要的任何字段的类型。无需实现自定义解组器,因为默认设置适合您。

例如这样的:

type Alpha struct {
    Id              int32
    Name            string
    SkipWhenMarshal string
}

func (a Alpha) MarshalJSON() ([]byte, error) {
    m := map[string]string{
        "id":   fmt.Sprintf("%d", a.Id),
        "name": a.Name,
        // SkipWhenMarshal *not* marshaled here
    }

    return json.Marshal(m)
}

您还可以使用别名类型使其更简单:

func (a Alpha) MarshalJSON() ([]byte, error) {
    type AA Alpha
    aa := AA(a)
    aa.SkipWhenMarshal = ""

    return json.Marshal(aa)
}

这里SkipWhenMarshal将输出,但它的值被清零。这种方法的优点是如果Alpha有很多字段,您不必重复它们。

于 2021-05-18T14:03:46.063 回答
1

你想要的根本无法用 encoding/json 完成。

但是你可以有两种类型

type AlphaIn struct { 
    Name string `json:"name"`
    Bar  string `json:"skipWhenMarshal"`
}

type AlphaOut struct { 
    Name string `json:"name"`
    Bar  string `json:"-"`
}

使用AlphaInencoding/json.Unmarshal 反序列化 JSON 并使用 encoding/json.MarshalAlphaOut将结构序列化为 JSON。

现在单独使用这个绝对是痛苦的,但是:结构标签在类型之间的转换中不起作用,它允许您通过简单的类型转换从 AlphaIn 转换为 AlphaOut:

var a AlphaIn = ...
var b AlphaOut = AlphaOut(a)

(一个更理智的命名方案将是AlphaAlphaToJSON或类似这样的东西。)

于 2021-05-18T14:40:44.363 回答
0

我会像这样编写一个自定义元帅函数:操场

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
    "strings"
)

type Alpha struct {
    Name            string `json:"name"`
    SkipWhenMarshal string `json:"SkipWhenMarshal,skip"`
}

func main() {
    var a Alpha
    a.Name = "John"
    a.SkipWhenMarshal = "Snow"

    out, _ := marshal(a)

    fmt.Println(string(out))

    var b Alpha
    json.Unmarshal([]byte(`{"Name":"Samwell","SkipWhenMarshal":"Tarly"}`), &b)

    fmt.Println(b)
}

// custom marshaling function for json that accepts an additional tag named skip to ignore the field
func marshal(v Alpha) ([]byte, error) {
    m := map[string]interface{}{}

    ut := reflect.TypeOf(v)
    uv := reflect.ValueOf(v)

    for i := 0; i < ut.NumField(); i++ {
        field := ut.Field(i)
        js, ok := field.Tag.Lookup("json")
        if !ok || !strings.Contains(js, "skip") {
            intf := uv.Field(i).Interface()
            switch val := intf.(type) {
            case int, int8, uint8:
                m[field.Name] = val
            case string:
                m[field.Name] = val
            }

        }
    }

    return json.Marshal(m)
}

它基本上将结构重建为没有跳过字段的映射,并将其传递给原始的 Marshal 函数。

现在只需将 SKIP 标签添加到任何字段,它应该可以工作。

你只需要改进这部分:

switch val := intf.(type) {

因为这仅假设您只有字符串或整数作为字段。处理更多类型会更理想。

于 2021-05-18T14:48:01.093 回答
0

你可以试试这个,即将结构分解成组件->组合

解组时使用 Beta 类型。它只会解组在 Beta 结构中定义的字段

type Beta struct {
  Name            string `json:"name"`
}

type Alpha struct {
    *Beta
    SkipWhenMarshal string `json:"skipWhenMarshal"`
}
于 2021-05-27T09:38:59.530 回答