结构体 & 方法
结构体 & 方法
结构体是由一些属性组成的复合数据类型,每个属性都具有名称,类型,结构体将属性组合在一起由程序进行处理
自定义类型:
在go语言中type声明一种新的类型,语法格式为:
type TypeName Formatter
注意:
新类型无法与老类型做对比,只能转为相等类型才能对比
初始化:
使用结构体创建的变量叫做对应结构体的实例或者对象
零值:
由每个属性对应的零值组成的结构体变量
结构体零值:
TypeName{}
type Counter int // 定义Counter为int类型
func main() {
var counter Counter // 定义变量为Counter类型
fmt.Println(counter) // 0
}
定义结构体
赋值
- 按顺序:需要按照结构体定义顺序为每个属性指定属性值
- 按属性名:不比为所有属性都设置属性值
结构体指针变量:
声明:
var structpoint *StructName
零值:
nil
赋值:
- 通过现有结构体变量:&var
- 通过结构体字面量:&StructName
- new
type User struct {
ID int
Name string
Bitrthday time.Time
tel string
Remark string
}
func main() {
var me User
fmt.Printf("%T\n", me) // main.User
fmt.Printf("%#v\n", me) // main.User{ID:0, Name:"", Bitrthday:time.Date(1, time.January, 1, 0, 0, 0, 0, tim
//e.UTC), tel:"", Remark:""}
// 初始化,必须给每个属性都设置值
var me2 User = User{1, "tcy", time.Now(), "110", "tcy"}
fmt.Println(me2)
// 初始化
var me3 User = User{}
fmt.Printf("%#v\n", me3)
// 通过属性名指定每个属性值,可以不按顺序指定,或者个别值不指定
var me4 User = User{ID: 1, Name: "twg", Bitrthday: time.Now(), tel: "119", Remark: "twg"}
fmt.Printf("%#v\n", me4)
// 结构体指针类型
var pointer *User
fmt.Printf("%T", pointer) //*main.User
fmt.Printf("%#v\n", pointer) //(*main.User)(nil)
var pointer2 *User = &me2
fmt.Printf("%#v", pointer2) // &main.User{ID:1, Name:"tcy", Bitrthday:time.Date(2022, time.May, 2, 9, 20, 32, 4
//46691800, time.Local), tel:"110", Remark:"tcy"}
// 获取结构体类型指针(方式一)
var pointer3 *User = &User{}
fmt.Printf("%#v\n", pointer3)
// 获取结构体类型指针(方式二),用new函数进行初始化结构体指针对象
var pointer4 *User = new(User)
fmt.Printf("%#v\n", pointer4)
var pointer5 *int = new(int)
fmt.Printf("%#v\n", pointer5)
}
结构体使用
type User struct {
ID int
Name string
Bitrthday time.Time
tel string
Remark string
}
func main() {
var me User = User{
Name: "tcy",
ID: 1,
Bitrthday: time.Now(),
tel: "110",
Remark: "tcy",
}
fmt.Println(me.ID, me.Name, me.tel)
// 修改结构体属性
me.tel = "120"
fmt.Printf("%#v\n", me)
me2 := &User{
ID: 2,
Name: "twg",
}
fmt.Printf("%T\n", me2) // *main.User
// 修改指针类型属性值(方式一)
me2.tel = "180"
fmt.Printf("%#v", me2)
// 修改指针类型属性值(方式二)
(*me2).Remark = "twg"
fmt.Printf("%#v", me2)
}
匿名结构体
没有结构体名称
方式一:
var name struct{Filename01 FileType01,Filedn FileldType}
方式二:
me2 := struct {
ID int
Name string
}
func main() {
// 匿名结构体
var me struct {
ID int
Name string
}
fmt.Printf("%T\n", me)
fmt.Printf("%#v\n", me) // struct { ID int; Name string }{ID:0, Name:""}
fmt.Println(me.ID) // 访问结构体
me.Name = "tcy" // 结构体修改
fmt.Println(me) // {0 tcy}
// 匿名结构体字面量初始化
me2 := struct {
ID int
Name string
}{1, "KK"}
fmt.Printf("%#v", me2) // struct { ID int; Name string }{ID:1, Name:"KK"}
}
结构体嵌入
结构体嵌入:结构体里面包含结构体
type Address struct {
Region string
Street string
No string
}
type User struct {
ID int
Name string
Addr Address // 结构体类型属性为另外一个结构体
}
func main() {
// 结构体给结构体内赋值(方式一)
addr := Address{"湖南省", "洪山街道", "586"}
me := User{
ID: 1,
Name: "tcy",
Addr: addr,
}
fmt.Printf("%#v\n", me) // main.User{ID:1, Name:"tcy", Addr:main.Address{Region:"湖南省", Street:"洪山街道"
//, No:"586"}}
// 结构体给结构体赋值(方式二)
me2 := User{
ID: 2,
Name: "twg",
Addr: Address{
"湖南省",
"长沙市",
"170",
},
}
fmt.Printf("%#v\n", me2)
// 访问
fmt.Println(me2.Addr)
// 修改
me2.Addr.Street = "益阳市"
fmt.Printf("%#v\n", me2)
}
指针结构体嵌入
type Address struct {
Region string
Street string
No string
}
type User struct {
ID int
Name string
Addr *Address // 声明一个结构体指针变量
}
func main() {
var me01 User
fmt.Printf("%#v\n", me01) //main.User{ID:0, Name:"", Addr:(*main.Address)(nil)}
//初始化
me02 := User{
ID: 1,
Name: "KK",
Addr: &Address{"湖南省", "长沙市", "145"},
}
fmt.Printf("%#v\n", me02) // main.User{ID:1, Name:"KK", Addr:(*main.Address)(0xc000074480)}
// 访问
fmt.Println(me02.Addr.Region) // 湖南省
// 修改
me02.Addr.Region = "北京市"
fmt.Printf("%#v\n", me02.Addr)
}
匿名结构体嵌入
匿名嵌入当出现属性名冲突,使用当前结构体中的属性
type Address struct {
Region string
Street string
No string
}
type User struct {
ID int
Name string
Addr Address // 结构体类型属性为另外一个结构体
}
type Employee struct {
User // 匿名嵌入,直接写入另外一个结构体名
Salary float64
}
func main() {
var me Employee
fmt.Printf("%T %#v\n", me, me) // main.Employee main.Employee{User:main.User{ID:0, Name:"", Addr:main.Address{Regi
//on:"", Street:"", No:""}}, Salary:0}
// 字面量初始化
me02 := Employee{
User: User{
ID: 1,
Name: "KK",
Addr: Address{
"湖南",
"长沙",
"001",
},
},
Salary: 1000,
}
fmt.Println(me02) // {{1 KK {湖南 长沙 001}} 1000}
// 访问属性
fmt.Println(me02.Name, me02.Addr.Street) // KK 长沙
// 修改属性
me02.User.Name = "twg"
fmt.Println(me02.Name, me02.Addr.Street) // twg 长沙
}
指针结构体匿名嵌入
type Address struct {
Region string
Street string
No string
}
type User struct {
ID int
Name string
Addr Address
}
type Employee struct {
*User // 指针类型匿名嵌入
Salary float64
Name string
}
func main() {
var me Employee
fmt.Printf("%#v\n", me) // main.Employee{User:(*main.User)(nil), Salary:0, Name:""}
// 初始化
me01 := Employee{
User: &User{
ID: 3,
Name: "tcy",
Addr: Address{
"湖南省",
"长沙市",
"001",
},
},
Salary: 10000,
Name: "tcy",
}
fmt.Printf("%#v\n", me01) // main.Employee{User:(*main.User)(0xc0000d8000), Salary:10000, Name:"tcy"}
// 访问
fmt.Println(me01.Name) // tcy
fmt.Println(me01.Addr) // {湖南省 长沙市 001}
}
可见性
type StructName struct{}
结构体:
结构体名称首字母大写,包外可见
结构体名称首字母小写,包外不可见
属性:
属性名称首字母大写,包外可见
属性名称首字母小写,包外不可见
方法
定义与调用
方法是添加了接受者的函数,接收者必须是自定义类型
type Dog struct { // 自定义类型Dog
Name string
}
// 为结构体Dog定义方法Call
func (dog Dog) Call() { // 无参数,无返回值
fmt.Printf("%s: 汪汪\n", dog.Name)
}
// 为结构体Dog定义方法SetName
func (dog Dog) SetName(name string) {
dog.name = name
}
func main() {
dog := Dog{"豆豆"}
dog.Call() // 调用方法
}
- 指针接收者 & 值接收者
声明:
func (dog *Dog) PSetName(name string) {
dog.name = name
}
调用:
(&dog).PSetName("大狗")
dog.Call()
说明:
当使用结构体指针对象调用接收者方法时,Go编译器会自动将指针对象“解引用” 。
当使用结构体对象调用指针接收者的方法时,Go编译器会自动将值对象“取引用” 为指针调用方法。
type Dog struct {
name string
}
func (dog Dog) Call() {
fmt.Printf("%s: 汪汪\n", dog.name)
}
func (dog Dog) SetName(name string) {
//dog.name = name // 方法体内改变属性,并不会影响全局
}
func (dog *Dog) PsetName(name string) {
dog.name = name
}
func main() {
dog := Dog{"tcy"}
dog.Call() // tcy: 汪汪
dog.SetName("ttt")
dog.Call() // tcy: 汪汪
// 修改方法中自定义类型属性值 方式一:
(&dog).PsetName("twg")
dog.Call() // twg: 汪汪
// 修改方法中自定义类型属性值 方式二:
pdog := &Dog{"豆豆"}
(*pdog).Call() // 豆豆: 汪汪
// 语法糖,go支持不用写&,但自动解引用只会发生在接受者位置
dog.PsetName("小机")
dog.Call() // 小机: 汪汪
}
方法的嵌入
type Address struct {
Region string
Street string
No string
}
func (addr Address) Addr() string {
return fmt.Sprintf("%s-%s-%s", addr.Region, addr.Street, addr.No)
}
type User struct {
ID int
Name string
Addr Address // 结构体类型属性为另外一个结构体
}
func (user User) User() string {
return fmt.Sprintf("[%d]%s: %s", user.ID, user.Name, user.Addr)
}
func main() {
var u User = User{
ID: 1,
Name: "kk",
Addr: Address{"湖南省", "长沙市", "001"},
}
fmt.Println(u.User()) // [1]kk: 湖南省-长沙市-001
}
匿名方法嵌入
type User struct {
id int
name string
}
func (user User) GetID() int {
return user.id
}
func (user User) GetName() string {
return user.name
}
// 当需要修改值,接受者必须设置为指针类型
func (user *User) SetID(id int) {
user.id = id
}
func (user *User) SetName(name string) {
user.name = name
}
type Employee struct {
User // 匿名结构体
Salary float64
}
func main() {
var me Employee = Employee{
User: User{1, "kk"},
Salary: 1000,
}
// 获取名字
fmt.Println(me.User.GetName()) // kk
fmt.Println(me.GetName()) // kk
me.SetName("tcy")
fmt.Println(me.GetName()) // tcy
}
方法值
创建方法值,就算修改对象,也不会影响到方法值。因为是值拷贝,值无法改变
什么叫方法值?
获取一个对象,将它的方法赋值给另外一个函数
type Dog struct {
name string
}
func (dog Dog) GetName() {
fmt.Printf("%s: 汪汪\n", dog.name)
}
func (dog *Dog) SetName(name string) {
dog.name = name
}
func main() {
dog := Dog{"tcy"}
me := dog.GetName // 值拷贝,将结果赋予给me,后续不会因为setname改变值
dog.SetName("twg") // 更改name为twg
me() // tcy: 汪汪
}
- 指针接收者
值可以改变
type Dog struct {
name string
}
// 修改为指针接受者,这里获取到真实数据
func (dog *Dog) GetName() {
fmt.Printf("%s: 汪汪\n", dog.name)
}
func (dog *Dog) SetName(name string) {
dog.name = name
}
func main() {
dog := &Dog{"tcy"} // 相当于连接到真实内存地址
me := dog.GetName // 赋予方法值
dog.SetName("twg") // 更改name为twg
me() // twg: 汪汪
}
方法表达式
type Dog struct {
name string
}
func (dog Dog) GetName() {
fmt.Printf("%s: 汪汪", dog.name)
}
func (dog *Dog) SetName(name string) {
dog.name = name
}
func main() {
m1 := Dog.GetName
m2 := (*Dog).SetName
fmt.Printf("%T %T\n", m1, m2) // func(main.Dog) func(*main.Dog, string)
dog := Dog{"豆豆"} // 豆豆: 汪汪
m1(dog)
m2(&dog, "小黑")
m1(dog) // 小黑: 汪汪
}
sort模块
切片排序
// 为切片排序
func main() {
list := [][2]int{{1, 2}, {5, 9}, {4, 5}, {6, 2}, {5, 8}} //2个元素,数组类型的切片
// 排序,使用数组第二个(索引为一)元素比较大小进行排序
sort.Slice(list, func(i, j int) bool {
return list[i][1] > list[j][1]
})
fmt.Println(list) // [[5 9] [5 8] [4 5] [1 2] [6 2]]
}
结构体排序
type user struct {
ID int
Name string
Score float64
}
func main() {
users := []user{{1, "kk", 6}, {2, "tcy", 9}, {3, "twg", 10}}
sort.Slice(users, func(i, j int) bool {
return users[i].Score < users[j].Score
})
fmt.Println(users) // [{1 kk 6} {2 tcy 9} {3 twg 10}]
}