Go语言结构体
结构体定义
type Point struct{
X int
Y float32
Z string
s []int
}
1.注意定义结构体时并没有分配内存空间
2.若结构体名称或者成员变量名称首字母为大写,代表这个字段的数据可以被其他包引用
小写为私有,只能在本包使用
内存布局以及分配机制
注:
- 结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。实例化即根据结构体定义的格式创建一份与格式一致的内存区域。
- 在创建一个结构体变量后,若没有给字段赋值,都对应一个零值(默认值),布尔类型是false、整型是0、字符串是""、数组类型默认的和其元素类型相关。
指针、slice、map的零值是nil,即没有分配空间。
type Person struct {
Name string
Age int
Score [5]float32
ptr *int
slice []int
map1 map[string]string
}
func main(){
var p1 Person
fmt.Println(p1)
}
所以若结构体变量中出现指针、slice、map,在创建结构体变量时,赋值的前提需要为其分配内存空间make(),不然会报错
p1.slice = make([]int,10)
p1.slice[0] = 666
p1.map1 = make(map[string]string)
p1.map1["key1"] = "value1"
var Ptr int
p1.ptr = new(int)
p1.ptr = &Ptr
- 结构体是值类型,即使是赋值拷贝,不同结构体的变量字段独立,一个结构体的变量字段的改变,不会影响另一个结构体变量的字段
type Animal struct {
Name string
Age int
}
func main(){
var a1 Animal
var a2 Animal
a1.Name = "monkey"
a1.Age = 10
a2 = a1
a2.Name = "dog"
fmt.Println("a1:",a1)
fmt.Println("a2:",a2)
}
//注意a1和a2是两个独立的数据空间
重要的栗子:
type Animal struct{
Name string
Age int
}
func main(){
var a1 Animal
a1.Name = "monkey"
a1.Age = 10
var a2 *Animal = &a1
fmt.Println((*a2).Age)
fmt.Println(a2.Age)
a2.Name = "lion"
fmt.Printf("a2.Name=%v a1.Name=%v \n",a2.Name,a1.Name)
fmt.Printf("(*a2).Name=%v a1.Name=%v \n",(*a2).Name,a1.Name)
fmt.Printf("a1的地址是:%p \n",&a1)
fmt.Printf("a2的地址是:%p a2的值是:%p \n",&a2,a2)
}
特别注意:不能像下面那样写,点.
号的运算优先级大于星号*
,若这样写会先用a2.Age,当然会成功访问,但随后的星号 * 出现会报错
var a2 *Animal = &a1
fmt.Printf(*a2.Age)
- 结构体的所有字段在内存中是连续的,如下,在我64位的系统里面,一个int型数据数据所占字节数为8个字节,如下结果(地址是16进制的),都是相隔8个字节连续分布的
type Animal struct{
Name int
Age int
}
type Family struct {
leftA,rightA Animal
}
/*
//若是定义的指针类型,这两个指针类型的本身地址也是连续的
//但是它们指向的地址不一定是连续的
type Family2 struct{
leftA,rigthA *Point
}
*/
func main(){
a1 := Family{Animal{10,20},Animal{10,19}}
fmt.Printf("a1.leftA.Name 的地址是:%p \n", &a1.leftA.Name)
fmt.Printf("a1.leftA.Age 的地址是:%p \n",&a1.leftA.Age)
fmt.Printf("a1.rightA.Name 的地址是:%p \n",&a1.rightA.Name)
fmt.Printf("a1.rightA.Age的地址是:%p \n",&a1.rightA.Age)
}
结构体实例化
①基本实例化形式
var ins T
1.T为结构类型,ins为结构体的实例
2.注意这里实例化一个ins,这个ins已经分配了内存空间
②创建指针类型的结构体
ins := new(T)
T为类型,可以是结构体、整型、字符串等
ins:T类型被实例化后保存到ins变量中,ins的类型为*T,属于指针
③取结构体的地址实例化
推荐使用 var p Point = Point{ }
ins := &T{}
T表示结构体类型
ins为结构体实例,类型为*T,为指针类型
以上三种实例化形式的栗子
type Point struct{
X int
Y string
Val *int
}
//基本实例化
//p1 := Person{10,"monkey",&xxx}
var p1 Point
p1.X = 10
p1.Y = "monkey"
//创建指针类型的结构体
//var p2 Point = new(Point)
p2 := new(Point)
//(*p2).X = 6
p2.X = 6
p2.Y = "monkey"
//取结构体地址实例化
//var p3 *Point := &Point{6,"monkey",&xxx}
//(*p3).X = 6
var version = 1
p3 := &Point{}
p3.X = 6
p3.Y = "monkey"
p3.Val = &version
取地址实例化是最广泛的一种结构体实例化方式,关于取地址实例化可用函数封装其初始化过程
func newPoint(x int,y string,val *int)*Point{
return &Point{
X: x,
Y: y,
Val:val,
}
}
var version int
ins = newPoint(
8,
"monkey",
&version
)
初始化结构体成员变量
使用键值对初始化结构体
type People struct{
name string
child *People
//relation由People类型取地址后,形成类型为*People的实例
relation := &People{
name:"爷爷"
child:&People{
name:"爸爸"
child:&People{
name:"我"
},
},
}
使用多个值的列表初始化结构体
要求具有一定的顺序
type Address struct{
Provice string
City string
ZipCode int
PhoneNumber string
}
addr := Address{
"四川",
"成都",
610102,
"12",
}
fmt.Println(addr)//{四川 成都 610102 12}
初始化匿名结构体
匿名结构体没有类型名称,无须通过type关键字定义就可以直接使用
package main
import "fmt"
func printMsgType(msg *struct{
id int
data string}){
fmt.Println("%T\n",msg)
}
func main(){
msg := &struct{
id int
data string
}{
1024,
"monkey",
}
printMsgType(msg)
}
结构体注意事项
- 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数、类型)
type A struct{
Num int
}
type B struct{
Num int
}
func main(){
var a A
var b B
a = A(b)//可以转换
}
- 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是可以相互转换
type Point struct{
x int
y int
}
type Pot Point
type integer int
func main(){
var p1 Point
var p2 Pot
// p2 = p1//这是错误的
p2 = Pot(p1)
var num1 integer = 6
var num2 int = 8
//num2 = num1//这是错误的
num2 = int(num1)
}
- 在前面结构体定义是提到过,“若结构体名称或者成员变量名称首字母为大写,代表这个字段的数据可以被其他包引用,小写为私有,只能在本包使用”,这里调用了包"encoding/json"的方法json.Marshal(),传入参数结构体Animal的一个变量,而结构体变量里的字段名是大写,即公有,即其可以调用其他包的方法,但是如果改成小写首字母,在输出时,json字符串为空
package main
import (
"encoding/json"
"fmt"
)
type Animal struct{
Name string `json:"name"`
Age int `json:"age"`
}
/*
type Animal struct{
name string
age int
*/
func main(){
monkey := Animal{"monkey",10}
jsonMon,err := json.Marshal(monkey)
if err!=nil{
fmt.Println("json处理错误",err)
}
fmt.Println(jsonMon)
fmt.Println(string(jsonMon))
}