第四篇:结构体
第四篇:结构体
目录
一、结构体的使用
结构体是一系列属性的集合。【没有方法】
1 有名结构体
// 定义结构体【在entity包中定义】
type Person struct {
Name string // 大写,外部包可以进行引用;小写,仅表明内部包可以使用
Age int //
Sex string
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import (
"day01/entity"
"fmt"
)
// 1 结构体的基本使用【访问结构体字段使用".",但是注意大小写】
func main() {
var per entity.Person // 生成一个结构体对象 【包名.结构体名】(大写代表外部包可以进行引用,小写仅表明内部包可以使用)
fmt.Println(per) // { 0 } 打印结构体对象
per.Name = "yangyi" // 结构体属性赋值
per.Age = 18
per.Gender = "male"
fmt.Println(per) // {yangyi 18 male}
}
// 2 结构体定义并附初值
var person1 entity.Person = entity.Person{Age: 18, Name: "yangyi"} // 指名道姓,可以不按位置,并且少传
person2 := entity.Person{"yangyi", 18, "male"} // 不指名道姓,必须按位置
在python每个文件就是一个模块。而go中的一个包可以想象成一个大的文件,在其中的名字不能重复。
2 匿名结构体
// 匿名结构体(定义在内部【函数,结构体】,仅使用一次。就像python中的匿名函数一样)
// 有什么用?
// 假如说有多个变量,一个一个用,还不如放到匿名结构体中,一个代表多个
school := struct { // 将匿名结构体赋值给一个变量【因为没有名字,变量只能用类型推导和简略声明两种方式】
SchoolId int64
SchoolName string
}{100, "ccut"} // 实例化匿名结构体
school.SchoolId = 99 // 修改匿名函数的值
3 结构体零值
属性的零值,值类型,参数传递属于copy传递【函数传参,修改,不会改变原来的】。简单来说,结构体传递属于值传递。
var person entity.Person = entity.Person{"yangyi", 18, "male"}
fmt.Println(person) // {yangyi 18 male}
test(person) // {lei 18 male}
fmt.Println(person) // {yangyi 18 male}
func test(person entity.Person) {
person.Name = "lei"
fmt.Println(person)
}
4 结构体指针
// 1 定义结构体指针
var person *entity.Person // 结构体指针
fmt.Println(person) // <nil> 指针的零值
// 2 定义并初始化
var person *entity.Person = &entity.Person{"yangyi", 18, "male"} // 定义一个结构体指针
person1 := &entity.Person{"yangyi", 18, "male"}
fmt.Println(person) // &{yangyi 18 male}
fmt.Println(person1) // &{yangyi 18 male}
// 修改属性值
// 第一种方式: 推荐
(*person).Name = "lei"
// 第二种方式: 不推荐,有歧义【语言层面自动进行处理】
person.Age = 20
fmt.Println(person) // &{lei 20 male}
5 匿名字段
匿名字段,内含匿名字段(字段没有名字),匿名字段的类型就是字段名,所以类型不能重复。
作用:变量提升。【其实就是面向对象的继承】
// 匿名字段,内含匿名字段(字段没有名字)
type Person struct {
string // 字段没有名字
Age int
Gender string
}
// 实例化匿名字段结构体对象
// 第一种方式: 按位置
person := Person{"yangyi", 18, "male"}
// 第二种方式: 按名字
person1 := Person{string:"yangyi", Age: 18, Gender: "male"} // 如果字段匿名,类型就是字段名【这个string有点过分了呀】
fmt.Println(person1.string) // yangyi 通过类型可以取到值。【哈哈】
6 结构体嵌套
结构体中套用结构体。
type Person struct {
Name string
Age int
Gender string
Hobby Hobby // 属性名是Hobby,属性类型为Hobby结构体
}
type Hobby struct {
HobbyId int
HobbyName string
}
// 按位置传递
// 第一种方式: 按位置
var person Person = Person{"yangyi", 18, "male", Hobby{2, "song"}}
// 第二种方式: 按名字
var person Person = Person{Name: "yangyi", Age: 18, Gender: "male", Hobby: Hobby{HobbyId: 2, HobbyName: "song"}}
// 结构体使用
fmt.Println(person.Name) // yangyi
fmt.Println(person.Hobby.HobbyName) // song
7 字段提升
字段提升像面向对象的继承。可以简单认为,字段提升就是面向对象的继承。【面向对象的继承: 子类继承父类,子类可以直接调用父类的方法】
type Person struct {
Name string
Age int
Gender string
Hobby // 这里将Hobby设置为匿名字段,此处仅为Hobby类型
}
type Hobby struct {
HobbyId int
HobbyName string
}
// 第一种方式: 按位置
var person Person = Person{"yangyi", 18, "male", Hobby{2, "song"}}
// 第二种方式: 按名字【此时Hobby: 中的Hobby是字段名】
var person Person = Person{Name: "yangyi", Age: 18, Gender: "male", Hobby: Hobby{HobbyId: 2, HobbyName: "song"}}
// 此处体现了字段提升的效果【匿名字段+结构体嵌套】
fmt.Println(person.Hobby.HobbyName) // song person.Hobby类似于面向对象中的super【java python中皆有】
fmt.Println(person.HobbyName) // song
如果结构体嵌套中,属性名重复,则可认为是派生,子类重写了父类中的方法。【不严谨的说明】
8 导出结构体和字段
大写字母开头,在外部包可以使用。
9 结构体相等性
- 结构体都是值类型
- 如果结构体中的每一个字段都是可比较的,则该结构体也是可比较的。
- 如果两个结构体变量的对应字段相等,则这两个变量也是相等的。
- 如果结构体包含不可比较字段,则结构体变量也不可比较。
// 属性全是值类型,可以进行比较
type Person struct {
Name string
Age int
Gender string
}
// 值类型直接==比较,引用类型只能跟nil用==比较,且引用类型不能匿名
person1 := Person{"yangyi"}
person2 := Person{"yangyi"}
fmt.Println(person1 == person2) // true
person1 := Person{"yangyi"}
person2 := Person{"yangyi", 18}
fmt.Println(person1 == person2) // false
二、方法的使用
1 方法的定义和使用
方法其实就是一个函数,在func
这个关键字和方法名中间加入了一个特殊的接收器类型。接收器可以是结构体类型或者是非结构体类型。接收器可以在方法的内部调用。
// 1) 定义一个结构体
type Person struct {
Name string // 字段没有名字
Age int
Gender string
}
// 2) 给结构体绑定一个方法【绑定给对象的方法】
func(p Person) tellName(){ // p就是python中的self,绑定给Person的结构体对象
fmt.Println(p.Name)
}
// python写法
def tell_name(self): // 其实p就相当于python中的self。方法就是绑定给类或者结构体的
pass
/* 方法和函数的区别 */
// 方法【对象.方法调用】
func (p Person)TellName() {
// 该方法类可以使用p
fmt.Println(p.Name)
}
// 函数【正常调用】
func TestName(p Person) {
fmt.Println(p.Name)
}
1.1 值类型接收器
// 修改名字
// 1)修改名字【错误,其实名字并没有改,因为结构体是值类型】
func (p Person) changeName(name string) {
p.Name=name
fmt.Println(p)
}
person.changeName("lei") // 即可修改名字【并没有修改】
1.2 指针类型接收器
func (p *Person) changeName(name string) {
(*p).Name=name // 第一种方式
p.Name=name // 第二种方式【C中指针是 p->name = name】
fmt.Println(p)
}
当拷贝一个结构体的代价过于昂贵时,这种情况下就需要使用指针类型接收器,只会传递一个指针到方法内部使用。
2 匿名字段方法提升
方法提升。【结构体嵌套+字段提升,其中嵌套的结构体中绑定了方法,就能实现方法提升】。如果方法名重复,优先使用子结构体的。
type Person struct {
Name string
Age int
Gender string
Hobby // 这里将Hobby设置为匿名字段,此处仅为Hobby类型
}
type Hobby struct {
HobbyId int
HobbyName string
}
// 给结构体绑定方法
func (p *Person) tellName(){
fmt.Println((*p).Name)
}
func (p *Hobby) tellHobbyName(){
fmt.Println((*p).HobbyName)
}
func main() {
person := Person{"yangyi", 18, "male", Hobby{222, "song"}}
person.tellName() // yangyi
person.tellHobbyName() // song 方法提升
person.Hobby.tellHobbyName() // song
}
// 在方法中使用指针接收器 与 在函数中使用指针参数
type Person2 struct {
Name string
Age int
Sex string
}
// 1)在方法中使用值接收器
func (p Person)printName() {
fmt.Println(p.Name)
}
// 2)在函数中使用值参数
func printName(p Person) {
fmt.Println(p.Name)
}
》》》》》》》》》》》》》》》》》待续》》》》》》》》》》》》》》》》》》》
文章标题:第四篇:结构体
文章链接:https://www.dianjilingqu.com/4185.html
本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:saisai#email.cn,感谢支持理解。
文章链接:https://www.dianjilingqu.com/4185.html
本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:saisai#email.cn,感谢支持理解。
THE END