package main
import "fmt"
type Cat struct {
Name string
Age int
Color string
}
func main() {
var cat1 Cat
cat1.Name = "小白"
cat1.Age = 1
cat1.Color = "白色"
fmt.Println(cat1)
fmt.Println(cat1.Name)
fmt.Println(cat1.Age)
fmt.Println(cat1.Color)
}
字段声明语法同变量,示例:字段名字段类型
字段的类型可以为:基本类型、数组或引用类型
在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值),规则同前面讲的一样:
布尔类型是false ,数值是0,字符串是""。
数组类型的默认值和它的元素类型相关,比如score [3]int则为[0,0,0] 指针,slice,和map的零值都是nil,即还没有分配空间。
不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个。
package main
import "fmt"
//如果结构体的字段类型是:指针,slice,和map的零值都是 nil ,即还没有分配空间
//如果需要使用这样的字段,需要先make,才能使用.
type Person struct {
Name string
Age int
Scores [5]float64
ptr *int
slice []int
map1 map[string]string
}
func main() {
//定义结构体
var p1 Person
fmt.Println(p1)
p1.slice = make([]int, 10)
p1.slice[0] = 100
p1.map1 = make(map[string]string)
p1.map1["key"] = "tom"
fmt.Println(p1)
}
方式1-直接声明案例演示: var person Person
方式2-{} 案例演示: var person Person = Person{}
方式3-* 案例: var person *Person= new (Person)
方式4-&案例: var person *Person = &Person
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
//方式一:
var p1 Person
fmt.Println(p1)
//方式二:
var p2 Person
p2.Name = "tom"
p2.Age = 12
fmt.Println(p2)
//方式三:
var p3 *Person = new(Person)
//因为p3是一个指针,因此标准的给字段赋值方式
//(*p3).Name = "tom" 也可以这样写 p3.Name = "tom"
//原因:go的设计者 为了程序员使用方便, 底层会对 p3.Name = "tom" 进行处理
//会给p3加上 取值运算 (*p3).Name = "tom"
(*p3).Name = "tom"
p3.Name = "john"
(*p3).Age = 30
fmt.Println(*p3)
//方式四:
var p4 *Person = &Person{"marry", 1}
//因为p4是指针,因此标准的访问字段的方法
//(*p4).Name = "tom"
//go的设计者为了程序员使用方便,也可以 p4.Name = "tom"
//原因和上面一样,底层会对 p4.Name = "tom" 进行处理, 会加上(*p4)
fmt.Println(*p4)
(*p4).Name = "tom"
p4.Name = "tom2"
(*p4).Age = 48
fmt.Println(*p4)
}
结构体的所有字段在内存中是连续的
package main
import "fmt"
type Point struct {
x int
y int
}
type Rect struct {
leftUp, rightDown Point
}
type Rect2 struct {
leftUp, rightDown *Point
}
func main() {
r1 := Rect{Point{1, 2}, Point{3, 4}}
//r1有4个int ,在内存中是连续分布的
fmt.Printf("r1.leftUp.x 地址 = %p r1.leftUp.y 地址= %p r1.rightDown.x 地址=%p r1.rightDown.y 地址=%p\n",
&r1.leftUp.x, &r1.leftUp.y, &r1.rightDown.x, &r1.rightDown.y)
r2 := Rect2{&Point{10, 20}, &Point{30, 40}}
//r2有两个 *point类型, 这两个*Point类型的本身地址也是连续的,
//但是他们指向的地址不一定是连续的
fmt.Printf("r2.leftUp 本身的地址 = %p r2.rightDown 本身的地址= %p\n",
&r2.leftUp, &r1.rightDown)
}
结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)
package main
import "fmt"
type A struct {
Num int
}
type B struct {
Num int
}
func main() {
var a A
var b B
a = A(b) // 可以转换 , 但是有要求,就是结构体的字段要完全一样(包括:名字,个数和类型)
fmt.Println(a, b)
}
结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列号和反序列化。
package main
import (
"encoding/json"
"fmt"
)
type Monster struct {
Name string `json:"name"` // 就是 struct tag
Age int `json:"age"`
Skill string `json:"skill"`
}
func main() {
//1.创建一Monster变量
monster := Monster{"牛魔王", 500, "芭蕉扇"}
//2.将monster变量序列化为JSON格式字符串
//json.Marshal 使用到反射
jsonStr, err := json.Marshal(monster)
if err != nil {
fmt.Println("错误")
}
fmt.Println("jsonStr = ", string(jsonStr))
}