Go语言学习笔记(十三)之结构体struct

19.面对对象1之struct结构体

Go中面向对象是通过struct来实现,struct是用户自定义的类型,首先需要定义struct

  1: type User struct {
  2: 	Username string
  3: 	Sex string
  4: 	Age int
  5: 	AvatarUrl string
  6: }

初始化方法1

  1: var user User
  2: user.Age = 18
  3: user.Username = "user01"
  4: user.Sex = ""
  5: user.AvatarUrl = "http://my.com/xxx.jpg"

初始化方法2
//也可以部分初始化,这样没有初始化的部分具体值就是对应数据的默认值

  1: var user User = User {
  2: 	"Username" : "user01",
  3: 	// "Age" : 18,
  4: 	"Sex" : "",
  5: 	"AvatarUrl" : "http://my.com/xxx.jpg",
  6: }

更简单的写法

  1: user := User {
  2: 	"Username": "user01",
  3: 	"Age": 18,
  4: 	"Sex":"",
  5: 	"AvatarUrl":"http://my.com/xxx.jpg",
  6: }

结构体类型的指针

// &User{}和new(User)本质上是一样的,都是返回一个结构体的地址

  1: var user01 *User = &User {}
  2: fmt.Pringln(user01)
  1: >>> &{  0 }

// 序列化的时候传入指针类型,节省内存,如果不传,就是复制了一个新的User。

  1: var user01 *User = &User {
  2: 	user01.Age = 18
  3: 	//等同于(*user01).Age = 18
  4: 	user01.Username = "user01"
  5: 	fmt.Printf("user01:%#v\n", user01)
  6: }
  1: >>> user01:&main.User{Username:"user01", Sex:"", Age:18, AvatarUrl:""}

struct内存布局

结构体的内存布局:占用一段连续的内存空间,每一块内存指向数据对应的地址

  1: type Test struct {
  2: 	A int32
  3: 	B int32
  4: 	C int32
  5: 	D int32
  6: }
  7: func main() {
  8: 	var t Test
  9: 	fmt.Printf("a addr:%p\n", &t.A)
 10: 	fmt.Printf("a addr:%p\n", &t.B)
 11: 	fmt.Printf("a addr:%p\n", &t.C)
 12: 	fmt.Printf("a addr:%p\n", &t.D)
 13: }
 14: >>> a addr:0xc00000c0b0
 15: a addr:0xc00000c0b4
 16: a addr:0xc00000c0b8
 17: a addr:0xc00000c0bc

结构体没有专门的构造函数,必要的话要自己写

  1: type User struct {
  2: 	Username string
  3: 	Sex string
  4: 	Age string
  5: 	AvatarUrl string
  6: }
  7: 
  8: func NewUser(username string,sex string,age int, avatar string) *User {
  9: 	// 第一种写法
 10: 	//user := &User {
 11: 		//Username : username,
 12: 		//Sex : sex,
 13: 		//Age : age,
 14: 		//AvatarUrl : avatar,
 15: 	//}
 16: 	//第二种写法
 17: 	user := new(User)
 18: 	user.Username = username
 19: 	user.Sex = sex
 20: 	user.Age = age
 21: 	user.AvatarUrl = avatar
 22: 	return user
 23: }
 24: 
 25: func main() {
 26: 	u := NewUser("user01", "", 18, "xxx.jpg")
 27: 	fmt.Printf("user=%#v\n", u)
 28: }
  1: >>> user=&main.User{Username:"user01", Sex:"", Age:18, AvatarUrl:"xxx.jpg"}

匿名字段

没有名字的字段

  1: type User struct {
  2: 	Username string
  3: 	Sex string
  4: 	int 
  5: 	string
  6: }
  7: 
  8: func main() {
  9: 	var user User
 10: 	user.Username = "user01"
 11: 	user.Sex = "man"
 12: 	user.int = 100
 13: 	user.string = "hello"
 14: 	fmt.Println(user)
 15: }
  1: >>> user=&main.User{Username:"user01", Sex:"", Age:18, AvatarUrl:"xxx.jpg"}
  2: 

结构体的嵌套

  1: type Address struct {
  2: 	Province string
  3: 	City string
  4: }
  5: 
  6: type User struct {
  7: 	Username string
  8: 	Sex string
  9: 	address Adress
 10: }
 11: 
 12: func main() {
 13: 	user := &User{
 14: 		Username:"user01",
 15: 		Sex:"man",
 16: 		address: Address{
 17: 			Province:"beijing",
 18: 			City:"beijing",
 19: 		},
 20: 	}
 21: 	fmt.Println(user)
 22: 	fmt.Printf("user%#v", user)
 23: }
  1: >>> &{user01 man {beijing beijing}}
  2: user&main.User{Username:"user01", Sex:"man", address:main.Address{Province:"beijing", City:"beijing"}}

// 格式化输出时加上#会让输出按照近似go语言的数据结构来。

字段冲突的问题
优先使用主结构体里->没有就去嵌套结构体里面找
字段可见性,大写表示公开访问,小写表示私有,不能跨包访问

tag是结构体的元信息

运行时可以通过反射的机制读出来

  1: type User struct {
  2: 	Usename string `json:"username", db:"user_name"`
  3: 	Sex string `json:"sex"`
  4: 	Age int `json:"age"`
  5: 	avatarUrl string
  6: 	CreateTime string
  7: }
  1: package main
  2: import (
  3: 	"encoding/json"
  4: 	"fmt"
  5: )
  6: type User struct {
  7: 	Username string `json:"username"`
  8: 	Sex string `json:"sex"`
  9: 	Score float32
 10: }
 11: func main()  {
 12: 	user := &User{
 13: 		Username:"user01",
 14: 		Sex:"",
 15: 		Score:99.2,
 16: 	}
 17: 	data, _ := json.Marshal(user)
 18: 	fmt.Printf("json str:%s\n", string(data))
 19: }
  1: >>> json str:{"username":"user01","sex":"","Score":99.2}

20.面对对象2

方法的定义:和其他的语言不一样,go语言中不是使用class这个关键词,而且也没有class这个关键词

  1: package main
  2: import "fmt"
  3: type People struct {
  4: 	Name string
  5: 	Country string
  6: }
  7: func (p People) Print() {
  8: 	fmt.Printf("name=%s country=%s\n", p.Name, p.Country)
  9: }
 10: func (p People) Set(name string, country string)  {
 11: 	p.Name = name
 12: 	p.Country = country
 13: }
 14: func main() {
 15: 	var p1 People = People {
 16: 		Name : "people01",
 17: 		Country: "china",
 18: 	}
 19: 	p1.Print()
 20: 	p1.Set("people2", "USA")
 21: 	p1.Print()
 22: }

//注意结果是不变的
//函数不属于任何类型,方法属于特定的类型。

  1: >>> name=people01 country=china
  2: name=people01 country=china

指针类型作为接受者

  1: package main
  2: import "fmt"
  3: type People struct {
  4: 	Name string
  5: 	Country string
  6: }
  7: func (p *People) Print() {
  8: 	fmt.Printf("name=%s country=%s\n", p.Name, p.Country)
  9: }
 10: func (p *People) Set(name string, country string)  {
 11: 	p.Name = name
 12: 	p.Country = country
 13: }
 14: func main() {
 15: 	var p1 People = People {
 16: 		Name : "people01",
 17: 		Country: "china",
 18: 	}
 19: 	p1.Print()
 20: 	p1.Set("people02", "USA")
 21: 	// 语法糖(&p1).Set("people02", "USA")
 22: 	p1.Print() 
 23: }
 24: >>> name=people01 country=china
 25: name=people2 country=USA

//注意结果已经改变了

  1: >>> name=people01 country=china
  2: name=people2 country=USA

匿名字段与继承

  1: type Animal struct {
  2: 	Name string
  3: 	Sex string
  4: }
  5: 
  6: func (a *Animal) Talk() {
  7: 	fmt.Printf("i'm talking, i m %s\n", a.Name)
  8: }
  9: 
 10: type Dog struct {
 11: 	Feet string
 12: 	*Animal
 13: }
 14: 
 15: func (d *Dog) Eat() {
 16: 	fmt.Println("dog is eatting")
 17: }
 18: 
 19: func main() {
 20: 	var d *Dog = &Dog {
 21: 		Feet:"four feets",
 22: 		Animal: &Animal {
 23: 			Name:"dog",
 24: 			Sex:"",
 25: 		},
 26: 	}
 27: 	d.Name = "dog01"
 28: 	d.Sex = ""
 29: 	d.Eat()
 30: 	d.Talk()
 31: }
  1: >>> dog is eating
  2: i'm talking, i m dog01

关于多重继承的冲突,与匿名字段的解决方法一样,通过指定的结构体与.运算符来调用。

Json序列化与反序列化

Json序列化

  1: package main
  2: 
  3: import (
  4: 	"encoding/json"
  5: 	"fmt"
  6: )
  7: 
  8: type Student struct {
  9: 	Id int
 10: 	Name string
 11: 	Sex string
 12: }
 13: 
 14: type Class struct{
 15: 	Name string
 16: 	Count int
 17: 	Student []*Student
 18: }
 19: func main() {
 20: 	classmate1 := &Class {
 21: 		Name :"101",
 22: 	}
 23: 	count := 0
 24: 	for i:=0;i<2;i++ {
 25: 		count += 1
 26: 		stu := &Student {
 27: 			Name:fmt.Sprintf("stu%d", i ),
 28: 			Sex : "man",
 29: 			Id : i,
 30: 		}
 31: 		classmate1.Count = count
 32: 		classmate1.Student = append(classmate1.Student, stu)
 33: 	}
 34: 	data, err := json.Marshal(classmate1)
 35: 	if err != nil{
 36: 		fmt.Println("failed")
 37: 		return
 38: 	}
 39: 	fmt.Printf("json:%s\n", string(data))
 40: }
  1: >>> json:{"Name":"101","Count":2,"Student":[{"Id":0,"Name":"stu0","Sex":"man"},{"Id":1,"Name":"stu1","Sex":"man"}]}

反序列化

把代码加到上面的main函数里面

  1: var rawJson = `{"Name":"101","Count":2,"Student":[{"Id":0,"Name":"stu0","Sex":"man"},{"Id":1,"Name":"stu1","Sex":"man"}]}`
  2: 
  3: var c1 *Class = &Class{}
  4: err = json.Unmarshal([]byte(rawJson), c1)
  5: if err != nil {
  6: 	fmt.Println("failed")
  7: }
  8: fmt.Printf("c1:%#v\n", c1)
  9: for _, v := range classmate1.Student {
 10: 	fmt.Printf("stu:%#v\n", v)
 11: }
  1: >>> c1:&main.Class{Name:"101", Count:2, Student:[]*main.Student{(*main.Student)(0xc00006c570), (*main.Student)(0xc00006c5a0)}}
  2: stu:&main.Student{Id:0, Name:"stu0", Sex:"man"}
  3: stu:&main.Student{Id:1, Name:"stu1", Sex:"man"}

小结:Go语言的数据类型分为四种:基础类型,聚合类型,引用类型,和接口类型。
基础类型:数字,字符串和布尔型
聚合类型:数组,结构体。聚合类型是通过组合简单类型而得到的。
引用类型:指针,slice,map,函数,以及channel。引用类型全都指向程序变量或者状态,操作引用数据就会遍及该数据的全部引用。
接口类型:单独说,略。

接下来博客上不写任何练习题了。

猜你喜欢

转载自www.cnblogs.com/haoqirui/p/10161950.html