关于 Golang 结构体
Golang type 关键词自定义类型和类型别名
自定义类型
type myInt int
上面表示的就是:将 myInt 定义为 int 类型,通过 type 关键字的定义,myInt 就是一种新的类型,
它具有 int 的特性。
类型别名
type TypeAlias = Type
type 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)
}
结构体定义初始化的几种方法
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()
}