关于 Golang 结构体
Golang type 关键词自定义类型和类型别名
自定义类型
type myInt int上面表示的就是:将 myInt 定义为 int 类型,通过 type 关键字的定义,myInt 就是一种新的类型,
它具有 int 的特性。
类型别名
type TypeAlias = Typetype byte = uint8type rune = int32
自定义类型和类型别名的区别
package main
import "fmt"
//自定义类型
type myInt int16
//类型别名
type myFloat = float32
func main() {
	var x myInt = 10
	fmt.Printf("%v %T\n", x, x) 
	var y myFloat = 12.3
	fmt.Printf("%v %T", y, y) 
}
 a 的类型是 main.newInt,表示 main 包下定义的 newInt 类型。b 的类型是 int 类型。
 a 的类型是 main.newInt,表示 main 包下定义的 newInt 类型。b 的类型是 int 类型。 
 结构体定义初始化的几种方法
Go语言中的基础数据类型可以表示一些事物的基本属性,
但是当我们想表达一个事物的全部或部分属性时,
这时候再用单一的基本数据类型明显就无法满足需求了,
Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,
这种数据类型叫结构体,英文名称struct
结构体的定义
type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
}其中:类型名:表示自定义结构体的名称,在同一个包内不能重复。字段名:表示结构体字段名。结构体中的字段名必须唯一。字段类型:表示结构体字段的具体类型。
package main
import "fmt"
type Car struct{
	name string
	color string
	price int
}
func main() {
	var s1 Car //实例化结构体
	s1.name = "朗逸"
	s1.color = "黑色"
	s1.price = 118000
	fmt.Printf("值:%v 类型:%T\n", s1, s1) 
	fmt.Printf("值:%#v 类型:%T", s1, s1)  
}

结构体实例化(第一种方法)
var 结构体实例 结构体类型package main
import "fmt"
type Car struct{
	name string
	color string
	price int
}
func main() {
	var s1 Car //实例化结构体
	s1.name = "朗逸"
	s1.color = "黑色"
	s1.price = 118000
	fmt.Printf("值:%v 类型:%T\n", s1, s1) 
	fmt.Printf("值:%#v 类型:%T", s1, s1)  
}
结构体实例化(第二种方法)
/注意:在 Golang 中支持对结构体指针直接使用.来访问结构体的成员。p2.name = "xx" 其 实在底层是(*p2).name = "xx"
package main
import "fmt"
type Car struct{
	name string
	color string
	price int
}
func main() {
	var s2 = new(Car)
	(*s2).name = "奥迪"
	(*s2).color = "黑色"
	(*&s2.price) = 1000
	fmt.Printf("值:%#v 类型:%T\n", s2, s2)
}package main
import "fmt"
type Car struct{
	name string
	color string
	price int
}
func main() {
	var s2 = new(Car)
	s2.name = "奥迪"
	s2.color = "黑色"
	s2.price = 1000
	fmt.Printf("值:%#v 类型:%T\n", s2, s2)
}这两个的写法实质是一样的;就是对开头的一个解释

从打印的结果中我们可以看出 s2 是一个结构体指针。
结构体实例化(第三种方法)
使用&对结构体进行取地址操作相当于对该结构体类型进行了一次 new 实例化操作。
	var s3 = &Car{}
	s3.name = "宝贝马"
	s3.color = "红"
	s3.price = 12000
	fmt.Printf("值:%#v 类型:%T\n", s3, s3)
结构体实例化(第四种方法)
键值对初始化
    var s3 = Car{
	name : "宝贝马",
	color: "红",
	price:12000,
	}
	fmt.Printf("值:%#v 类型:%T\n", s3, s3)注意:最后一个属性的,要加上逗号(键值对的需要加逗号)
结构体实例化(第五种方法)
		var s5 = &Car{
		name : "宝贝马",
		color: "红",
		}
		fmt.Printf("值:%#v 类型:%T\n", s5, s5) 
 
 结构体实例化(第六种方法)
使用值的列表初始化
	var s6 = &Car{
	"宝贝马",
	"红",
	100000,
	}
	fmt.Printf("值:%#v 类型:%T\n", s6, s6)
初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:
使用这种格式初始化时,需要注意:
结构体是值类型还是引用类型
值类型 : 改变变量副本值的时候,不会改变变量本身的值 (数组、基本数据类型、结构体)
引用类型:改变变量副本值的时候,会改变变量本身的值 (切片、map)
来个案例实验一下:(看副本改变,主体会不会改变)
/*
	值类型 : 改变变量副本值的时候,不会改变变量本身的值 (数组、基本数据类型、结构体)
	引用类型:改变变量副本值的时候,会改变变量本身的值  (切片、map)
*/
package main
import "fmt"
type Car struct{
	Name string
	Color string
	Price int64
}
func main() {
	var s1 = Car{
		"奥迪迦",
		"红",
		187123,
	}
	s2 := s1
	s2.Name = "帕莎特"
	fmt.Printf("%#v\n", s1) 
	fmt.Printf("%#v", s2) 
}
结构体是值类型,改变副本不会改变其主的内存值
结构体方法和接收者
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
    函数体
}例如,Person 类型的接收者变量应该命名为 p,Connector 类型的接收者变量应该命名为 c 等。
值类型的接收者
package main
import "fmt"
 type Car struct{
	Name string
	Color string
	Price int32
 }
 func (c Car) PrintInfo(){
	fmt.Printf("车辆名称:%v 颜色为:%v 价格为:%v\n",c.Name,c.Color,c.Price)
 }
func main() {
	var c1 = new(Car)
	c1.Name = "奥托"
	c1.Color = "黑"
	c1.Price = 123423
	c1.PrintInfo()
	var c2 = Car{
		"斑马",
		"红",
		123143,
	}
	c2.PrintInfo()
	
}

指针类型的接收者
指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针
package main
import "fmt"
 type Car struct{
	Name string
	Color string
	Price int32
 }
 func (c Car) PrintInfo(){
	fmt.Printf("车辆名称:%v 颜色为:%v 价格为:%v\n",c.Name,c.Color,c.Price)
 }
 func (c1 *Car) SetInfo(name string,color string){
	c1.Name = name
	c1.Color = color
 }
func main() {
	var c1 = new(Car)
	c1.Name = "奥托"
	c1.Color = "黑"
	c1.Price = 123423
	c1.PrintInfo()
	var c2 = Car{
		"斑马",
		"红",
		123143,
	}
	c2.PrintInfo()
	c1.SetInfo("宝贝马","绿")
	c1.PrintInfo()
	
}

给任意类型添加方法
package main
import "fmt"
//注意事项: 非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。
type MyInt int
func (m MyInt) PrintInfo() {
	fmt.Println("我是自定义类型里面的自定义方法")
}
func main() {
	var a MyInt = 20
	a.PrintInfo()
}
注意事项: 非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法
结构体的匿名字段
结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段
匿名字段默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个
package main
import "fmt"
type Car struct{
	string
	int
}
func main() {
	c := Car{
		"法拉奔",
		123123,
	}
	fmt.Printf("汽车品牌:%v,价格为:%v",c.string,c.int)
}
 
 
嵌套结构体
结构体的字段类型可以是:基本数据类型、也可以是切片、Map 以及结构体
如果结构体的字段类型是: 指针,slice,和map的零值都是 nil ,即还没有分配空间
如果需要使用这样的字段,需要先make,才能使用.
嵌套指针;映射
案例如下:
package main
import "fmt"
type Car struct{
	Name string
	Price int
	Seller []string
	Buyer map[string]string
}
func main() {
	var c Car
	c.Name = "宝贝马"
	c.Price = 1231334
	c.Seller = make([]string,3,10) // 指针,slice,和map的零值都是 nil ,即还没有分配空间;如果需要使用这样的字段,需要先make,才能使用.
	c.Seller[0] = "卫宫士郎"
	c.Seller[1] = "远坂樱"
	c.Seller[2] = "鸣人"
	c.Buyer = make(map[string]string)
	c.Buyer["宫本"] = "已购"
	c.Buyer["宋璇"] = "已购"
	fmt.Printf("%#v\n",c)
	fmt.Println("----------------------------")
	fmt.Printf("%v\n",c.Buyer)
}

结构体嵌套
package main
import "fmt"
/*
结构体嵌套
*/
type Person struct{
	Name string
	Age int
	Infomation 
}
type Infomation struct{
	Address string
	Country string
}
func main() {
	var p Person
	p.Name = "奥特曼"
	p.Age = 21
	p.Infomation.Address = "m78"
	p.Infomation.Country = "光"
	
	fmt.Printf("%#v",p)
}

嵌套匿名结构体
package main
import "fmt"
type Person struct{
	Name string
	Age int
	Infomation
}
type Infomation struct{
	City string
	Country string
}
func main() {
	var a Person
	a.Name = "奥特曼"
	a.Age = 12
	a.Country = "M78"
	a.City = "光"
	fmt.Printf("%v\n", a)
	fmt.Printf("%#v\n", a)
	fmt.Println(a.Infomation.City)
}

//当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。
 
 
package main
import "fmt"
type Person struct{
	Name string
	Age int
	Hobby string
	Infomation
}
type Infomation struct{
	City string
	Country string
	Hobby string
}
func main() {
	var a Person
	a.Name = "奥特曼"
	a.Age = 12
	a.Country = "M78"
	a.City = "光"
	a.City = "日本" //当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。
	a.Hobby = "唱跳"
	a.Infomation.Hobby = "睡觉"
	fmt.Printf("%#v\n", a)
	
}

关于嵌套结构体的字段名冲突
package main
import "fmt"
type Persion struct{
	Name string
	// Hobby string
	Information
	Realation
	
}
type Information struct{
	Hobby string
}
type Realation struct{
	Hobby string
}
func main() {
	var p Persion
	p.Name = "奥特"
	p.Hobby = "唱跳"
	fmt.Printf("%#v\n", p)
	
}

找不到是哪个结构体内的hobby
	var p Persion
	p.Name = "奥特"
	// p.Hobby = "唱跳"
	p.Information.Hobby= "唱跳"
	fmt.Printf("%#v\n", p)
结构体的继承
Go 语言中使用结构体也可以实现其他编程语言中的继承。
package main
import "fmt"
//父结构体
type Faher struct{
	Name string
}
 
func (a Faher) fn1(){
	fmt.Printf("%v发动x射线\n",a.Name)
}
//子结构体
type Son struct{
	Fight string
	Faher //结构体嵌套 继承
}
func (s Son) fn2(){
	fmt.Printf("%v超人飞踢",s.Name)
}
func main() {
	var c = Son{
		Faher: Faher{
			Name: "奥托之父",
		},
	}
	c.fn1()
	c.fn2()
}
 指针类型
 指针类型
 
 
package main
import "fmt"
//父结构体
type Faher struct{
	Name string
}
 
func (a Faher) fn1(){
	fmt.Printf("%v发动x射线\n",a.Name)
}
//子结构体
type Son struct{
	Fight string
	*Faher //结构体嵌套 继承
}
func (s Son) fn2(){
	fmt.Printf("%v超人飞踢",s.Name)
}
func main() {
	var c = Son{
		Faher: &Faher{
			Name: "奥托之父",
		},
	}
	c.fn1()
	c.fn2()
}




















