最近技术栈一直在更新,从Perl到Nodejs,再到golang,技术在不断的转换,技术思路迥异。从CVS、SVN到Git菜鸟,再到一般Git版本管理问题顺手能够解决,谈不上多大的成就感,但是独立解决问题后的愉悦永远值得回味。
通过学习这些新技术栈,我深刻体会到对技术人员来说,迎接变化,拥抱变化才是快速适应社会需求的根本技能。
背景
最近一个项目需要对Go的结构体中interface{}字段进行扩展实例化,如果修改interface类型字段为目标结构体类型,问题能够解决了,但是却会再不需要引入扩展字段调用时填充空值,这时候interface{}类型就能够大显身手。
实践
扩展Location interface{}字段,使其实例化
package tjson
import (
"encoding/json"
"fmt"
)
type Server struct {
ServerName string
ServerIP string
Location interface{}
}
type Loc1 struct {
City string
Zip string
}
type Loc2 struct {
City string
Province string
Zip string
}
type S struct {
Servers []Server
}
// Tjson Test interface node which will bring different object in
func Tjson() {
var s S
s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
loc1 := Loc1{
City: "Shanghai",
Zip: "200001",
}
s.Servers[0].Location = loc1
s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.0.2"})
loc2 := &Loc2{
Province: "Hebei",
City: "Xingtai",
Zip: "005400",
}
s.Servers[1].Location = loc2
// General json Marshal
// b, err := json.Marshal(s)
// Beautiful json Marshal
b, err := json.MarshalIndent(s, "", " ")
if err != nil {
fmt.Println("json err:", err)
}
fmt.Println(string(b))
}
测试代码
package tjson
import "testing"
func TestTjson(t *testing.T) {
Tjson()
}
go test结果
我们可以从生成JSON结果看出,server结构中Location interface{}字段分别被两个不同结构体Loc1, Loc2扩展,并实例化。
代码下载: https://github.com/MarsBighead/garden/tree/master/test/tjson
分析
Go语言接口(interface)特性决定了,任何类型(包括基础类型如bool、int、string等)都可以赋值给空接口(interface{}, 参考2)。
基于interface{}的特性,所以Location既可以被结构体Loc1实例化,又可以被结构体Loc2实例化。结构体S通过具名字段聚合,实现了结构体Server[]数组镶嵌,这样我们再实例化两个S元素时候可以分别对Server的Location interface{}字段实现不同结构体的实例话,并且能够得到很明显的对比效果。
interface{}的实例化实验证实了Go语言interface类型是Go语言的一大特性,恰如hash(哈希)至于Perl,字典之于Python。
参考资料
- Go Web编程 7.2 JSON处理
- Go语言圣经 http://docs.ruanjiadeng.com/gopl-zh/ch7/ch7-05.html
- Go语言程序设计 Mark Summerfield, etc, 许式伟等译。