避免/保护它的一种简单而常见的方法是使用type 关键字创建一个新类型,并使用类型conversion 传递此类型的值(该值可能是您的原始值, 类型转换是可能的,因为新类型将原始类型作为其基础类型)。
这是因为type 关键字创建了一个新类型,并且新类型将有零个方法(它不会“继承”基础类型的方法)。
这会产生一些运行时开销吗?编号引用自Spec: Conversions:
特定规则适用于数字类型之间或字符串类型之间的(非常量)转换。这些转换可能会更改x 的表示并产生运行时成本。 所有其他转换仅更改x 的类型,但不会更改其表示形式。
让我们看一个例子。我们有一个带有数字Age 的Person 类型,我们要确保Age 不能为负数(小于0)。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func (p *Person) UnmarshalJSON(data []byte) error {
type person2 Person
if err := json.Unmarshal(data, (*person2)(p)); err != nil {
return err
}
// Post-processing after unmarshaling:
if p.Age < 0 {
p.Age = 0
}
return nil
}
测试它:
var p *Person
fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":10}`), &p))
fmt.Println(p)
fmt.Println(json.Unmarshal([]byte(`{"name":"Bob","age":-1}`), &p))
fmt.Println(p)
输出(在Go Playground 上试试):
<nil>
&{Bob 10}
<nil>
&{Bob 0}
当然,同样的技术也适用于自定义编组 (MarshalJSON()):
func (p *Person) MarshalJSON() ([]byte, error) {
// Pre-processing before marshaling:
if p.Age < 0 {
p.Age = 0
}
type person2 Person
return json.Marshal((*person2)(p))
}
测试它:
p = &Person{"Bob", 10}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
p = &Person{"Bob", -1}
fmt.Println(json.NewEncoder(os.Stdout).Encode(p))
输出(在同一个Go Playground 示例上):
{"name":"Bob","age":10}
<nil>
{"name":"Bob","age":0}
<nil>
一个非常相似的问题是,当您为 fmt 包的自定义文本表示定义 String() string 方法时,您想使用您修改的默认字符串表示。在此处阅读更多信息:The difference between t and *t