自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义
type newint int
通过type
关键字的定义,newint
就是一种新的类型,它具有int
一切的特性。
type byte = uint8
type rune = int32
区别:
type newint int
type nwt = int
func main() {
var a newint
var b nwt
fmt.Printf("%T\t, value of a:%#v\n", a, a) //main.newint
fmt.Printf("%T\t\t, value of b:%b", b, b) //int
}
/*
main.newint , value of a:0
int , value of b:0
*/
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…...
}
type student struct{
name string
age int
idcard int16
city string
}
//或者
type student struct{
name, city string
age int
idcard int16
}
只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。
结构体本身也是一种类型,我们可以像声明内置类型一样使用var
关键字声明结构体类型。
var s1 student
s1.age = 18
s1.city = "hangzhou"
fmt.Println(s1)
可以通过使用new
关键字对结构体进行实例化,得到的是结构体的地址
var s2 = new(student)
(*s2).age = 18
(*s2).city = "liaoning"
fmt.Printf("%#v", s2)
go有语法塘
可以不用写取地址
var s2 = new(student)
s2.age = 18
s2.city = "liaoning"
fmt.Printf("%#v", s2)
没有初始化的结构体,其成员变量都是对应其类型的零值。
s3 := student{
age: 18,
idcard: 22222,
city: "hhhhh",
}
fmt.Printf("%T, value:%#v", s3, s3)
//main.student, value:main.student{name:"", city:"hhhhh", age:18, idcard:22222}
对指针进行结构体初始化
s3 := &student{
age: 18,
idcard: 22222,
city: "hhhhh",
}
fmt.Printf("%T, value:%#v", s3, s3)
//main.student, value:main.student{name:"", city:"hhhhh", age:18, idcard:22222}
s4 := student{
"xs",
18,
22222,
"hangz",
}
fmt.Println(s4)
结构体占用一段连续的内存
struct
是值类型
如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。
type animal struct {
name string
age int
habit string
}
func newanimal(name string, age int, habit string) *animal {
return &animal{
name: name,
age: age,
habit: habit,
}
}
s5 := newanimal("xiaobaisu", 18, "jjj")
有点类似于python
中的self
,按我的理解有点类似于类方法,而结构体相当于类
func (接收者变量 接收者类型‘一般就是结构体’) 方法名(参数列表) (返回参数) {
函数体
}
//接受者变量一般是接受者类型首字母小写
func (p person) sayname() {
fmt.Println(p.name, "hello")
}
type person struct {
name string
age int
married bool
}
func (p person) sayname() {
fmt.Println(p.name, "hello")
}
//直接初始化结构体
func main() {
p2 := person{
name: "小黄",
age: 3,
married: false,
}
p2.sayname()
}
//按构造函数方式初始化
func newperson(name string, age int, married bool) *person {
return &person{
name: name,
age: age,
married: married,
}
}
func main() {
p := newperson("大黄", 17, false)
p.sayname()
}
方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。
SetName, SetAge
注意:指针类型
func (p *person) setage(age int) {
p.age = age
}
不会修改变量本身
func (p person) setage2(age int) {
p.age = age
}
p.sayname()
p.setage(188)
p.sayname()
p.setage2(89)
p.sayname()
/*
大黄 hello, age is 17
大黄 hello, age is 188
大黄 hello, age is 188
*/
type Address struct {
province string
id int32
}
//暴露person
type Person struct {
name string
age int
address Address
}
func main() {
var p = Person{
name: "大黄",
age: 18,
address: Address{
province: "东莞",
id: 401000,
},
}
fmt.Printf("%#v type:%T", p, p)
}
当访问结构体成员时会先在结构体中查找该字段,找不到再去嵌套的匿名字段中查找。
type Agency struct {
city string
area int
}
type Address struct {
province string
id int32
Agency
}
//暴露person
type Person struct {
name string
age int
Address
}
func main() {
var p Person
p.name = "小黄"
p.age = 15
p.Agency.area = 78
p.city = "小黄"
fmt.Println(p)
}
为了避免歧义需要通过指定具体的内嵌结构体字段名。
type Address struct {
province string
id int32
city string
}
//Email 邮箱结构体
type Email struct {
Account string
city string
}
//暴露person
type Person struct {
name string
age int
Address
Email
}
func main() {
var p Person
p.name = "小黄"
p.age = 15
p.Address.city = "小黄"
p.Email.city = "小白"
fmt.Println(p)
}
//定义Animal
type Animal struct {
name string
age int
}
type Dog struct {
addr string
*Animal
}
//动物类方法
func (a *Animal) run(speed int) {
fmt.Println(a.name, "-run speed at:", speed)
}
//狗类方法
func (d *Dog) lookdoor() {
fmt.Println(d.name, "can lookdoor")
}
func main() {
var dogson = &Dog{
addr: "xiao",
Animal: &Animal{
name: "大黄",
age: 15,
},
}
dogson.run(15)
dogson.lookdoor()
}
json
序列化//Student学生
type Student struct {
Name string
Age int
Id int
}
//Class班级
type Class struct {
Title string
Students []*Student
}
func main() {
c := Class{
Title: "101",
Students: make([]*Student, 0, 200),
}
for i := 0; i < 10; i++ {
stu := &Student{
Name: fmt.Sprintf("stu%02d", i),
Age: 18,
Id: i,
}
c.Students = append(c.Students, stu)
}
//序列化
data, err := json.Marshal(c)
if err != nil {
fmt.Println("json marshal err")
return
}
fmt.Printf("json:%s\n", data)
//反序列化
str := `{"Title":"101","Students":[{"Name":"stu00","Age":18,"Id":0},{"Name":"stu01","Age":18,"Id":1},{"Name":"stu02","Age":18,"Id":2},{"Name":"stu03","Age":18,"Id":3},{"Name":"stu04","Age":18,"Id":4},{"Name":"stu05","Age":18,"Id":5},{"Name":"stu06","Age":18,"Id":6},{"Name":"stu07","Age":18,"Id":7},{"Name":"stu08","Age":18,"Id":8},{"Name":"stu09","Age":18,"Id":9}]}`
cc := &Class{}
err = json.Unmarshal([]byte(str), cc)
if err != nil {
fmt.Println("json unmarshal failed")
return
}
fmt.Printf("%#v\n", cc)
}
Tag
是结构体的元信息,可以在运行的时候通过反射的机制读取出来。 Tag
在结构体字段的后方定义,由一对反引号包裹起来,
type Student struct {
Name string `json:"name"`
Age int `json:"age"`
Id int
}
键与值使用冒号分隔,值用双引号括起来。