第四篇:结构体

第四篇:结构体

目录

一、结构体的使用

结构体是一系列属性的集合。【没有方法】

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,感谢支持理解。
THE END
< <上一篇
下一篇>>