Go基础——结构体

11.结构体

11.1自定义类型

自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义

type newint int

通过type关键字的定义,newint就是一种新的类型,它具有int一切的特性。

11.2类型别名

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
*/

11.3结构体定义

type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    …...
}
type student struct{
	name string
	age int
	idcard int16
	city string
}
//或者
type student struct{
	name, city string
	age int
	idcard int16
}

11.4结构体实例化

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。

结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型。

	var s1 student
	s1.age = 18
	s1.city = "hangzhou"
	fmt.Println(s1)

11.4.1创建指针类型结构体

可以通过使用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)

11.5结构体初始化

没有初始化的结构体,其成员变量都是对应其类型的零值。

11.5.1使用键值对

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}

11.5.2使用值的列表进行初始化

  1. 必须初始化结构体的所有字段。
  2. 初始值的填充顺序必须与字段在结构体中的声明顺序一致。
  3. 该方式不能和键值初始化方式混用。
s4 := student{
		"xs",
		18,
		22222,
		"hangz",
	}
fmt.Println(s4)

结构体占用一段连续的内存

11.6构造函数

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")

11.7方法与接受者

有点类似于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()
}

方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。

11.7.1指针类型接受者来修改变量SetName, SetAge

注意:指针类型

func (p *person) setage(age int) {
	p.age = age
}

11.7.2值类型接受者

不会修改变量本身

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
	*/

11.7.3什么时候使用指针类型

  1. 需要修改接收者中的值
  2. 接收者是拷贝代价比较大的对象
  3. 如果某个方法使用指针接收者,那么其他的方法也应该使用指针接收者保证一致性。

11.8结构体嵌套

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)
}

11.8.1嵌套匿名字段

当访问结构体成员时会先在结构体中查找该字段,找不到再去嵌套的匿名字段中查找。

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)
}

11.8.2嵌套结构体的字段名冲突

为了避免歧义需要通过指定具体的内嵌结构体字段名。

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)
}

11.9继承

//定义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()
}

11.10结构体与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
}

键与值使用冒号分隔,值用双引号括起来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值