关于 Golang 结构体
Golang 中没有“类”的概念,Golang 中的结构体和其他语言中的类有点相似。和其他面向对
象语言中的类相比,Golang 中的结构体具有更高的扩展性和灵活性。
Golang 中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全
部或部分属性时,这时候再用单一的基本数据类型就无法满足需求了,Golang 提供了一种
自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称 struct。
也就是我们可以通过 struct 来定义自己的类型了。
type myInt int
type TypeAlias = Type
自定义类型和类型别名的区别
类型别名与自定义类型表面上看只有一个等号的差异,我们可以通过下面的这段代码来理解它们
之间的区别。
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)
}
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)
}
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)
使用这种格式初始化时,需要注意:
1.必须初始化结构体的所有字段。
2.初始值的填充顺序必须与字段在结构体中的声明顺序一致。
3.该方式不能和键值初始化方式混用。
结构体是值类型还是引用类型
值类型 : 改变变量副本值的时候,不会改变变量本身的值 (数组、基本数据类型、结构体)
引用类型:改变变量副本值的时候,会改变变量本身的值 (切片、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)
}
结构体是值类型,改变副本不会改变其主的内存值
结构体方法和接收者
在 go 语言中,没有类的概念但是可以给类型(结构体,自定义类型)定义方法。所谓方法
就是定义了接收者的函数。接收者的概念就类似于其他语言中的 this 或者 self。
方法的定义格式如下:
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}
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)
}
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)
}
比如上面的,我们可以直接在a中赋值information的数据
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)
}
var p Persion
p.Name = "奥特"
// p.Hobby = "唱跳"
p.Information.Hobby= "唱跳"
fmt.Printf("%#v\n", p)
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()
}