定义
结构体定义
// 声明结构体
type Vertex struct {
// 结构体的属性,同样遵循大写导出,小写私有的原则
X, Y int
z bool
}
// 也可以声明匿名/隐式结构体
point := struct {
X, Y int
}{1, 2}
// 声明空指针
var v *Vertex = new(Vertex)
// 显式声明键
var v = Vertex{X: 1, Y: 2}
// 声明数组
var v = []Vertex{{1,2},{5,2},{5,5}}
// 创建结构体实例
var v = Vertex{1, 2}
// 读取或者设置属性
v.X = 4;
方法的声明也非常简洁,只需要在 func 关键字与函数名之间声明结构体指针即可,该结构体会在不同的方法间进行复制:
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// Call method
v.Abs()
对于那些需要修改当前结构体对象的方法,则需要传入指针:
func (v *Vertex) add(n float64) {
v.X += n
v.Y += n
}
结构体默认值
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
结构体标签
结构体的字段除了名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。比如在我们解析 json 或生成 json 文件时,常用到 encoding/json 包,它提供一些默认标签,例如:omitempty 标签可以在序列化的时候忽略 0 值或者空值。而 -
标签的作用是不进行序列化,其效果和和直接将结构体中的字段写成小写的效果一样。
type Info struct {
Name string
Age int `json:"age,omitempty"`
Sex string
}
在序列化和反序列化的时候,也支持类型转化等操作:
type Info struct {
Name string
// 这样生成的json对象中,age就为字符串
Age int `json:"age,string"`
Sex string
}
在 Go 中,我们可以使用 reflect 包来获取自定义的字段信息:
package main
import (
"fmt"
"reflect"
)
const tagName = "Testing"
type Info struct {
Name string `Testing:"-"`
Age int `Testing:"age,min=17,max=60"`
Sex string `Testing:"sex,required"`
}
func main() {
info := Info{
Name: "benben",
Age: 23,
Sex: "male",
}
// 通过反射,我们获取变量的动态类型
t := reflect.TypeOf(info)
fmt.Println("Type:", t.Name())
fmt.Println("Kind:", t.Kind())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i) // 获取结构体的每一个字段
tag := field.Tag.Get(tagName)
fmt.Printf("%d. %v (%v), tag: '%v'\n", i+1, field.Name, field.Type.Name(), tag)
}
}
结构体的内存布局
Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。不像 Java 中的引用类型,一个对象和它里面包含的对象可能会在不同的内存空间中,这点和 Go 语言中的指针很像。下面的例子清晰地说明了这些情况:
type Rect1 struct {Min, Max Point }
type Rect2 struct {Min, Max *Point }