结构体 & 方法

结构体 & 方法

结构体是由一些属性组成的复合数据类型,每个属性都具有名称,类型,结构体将属性组合在一起由程序进行处理

自定义类型:

在go语言中type声明一种新的类型,语法格式为:

type TypeName Formatter

注意:

新类型无法与老类型做对比,只能转为相等类型才能对比

初始化:

使用结构体创建的变量叫做对应结构体的实例或者对象

零值:

由每个属性对应的零值组成的结构体变量

结构体零值:

TypeName{}

type Counter int				// 定义Counter为int类型

func main() {
	var counter Counter			// 定义变量为Counter类型
	fmt.Println(counter)		        // 0
}

定义结构体

赋值

  1. 按顺序:需要按照结构体定义顺序为每个属性指定属性值
  2. 按属性名:不比为所有属性都设置属性值

结构体指针变量:

声明:

var structpoint *StructName

零值:

nil

赋值:

  1. 通过现有结构体变量:&var
  2. 通过结构体字面量:&StructName
  3. 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}]
}

posted @ 2022-05-04 17:16  元气少女郭德纲!!  阅读(58)  评论(0编辑  收藏  举报