当前位置:网站首页>【Golang】快速复习指南QuickReview(六)——struct
【Golang】快速复习指南QuickReview(六)——struct
2022-06-23 19:45:00 【DDGarfield】
实际编程时,经常需要用相关的不同类型的数据来描述一个数据对象。C#中有类(Class),结构(Struct),当然类就不介绍了。Golang中叫结构体(C,C++好像还是结构体),但是单词还是Struct,无论是在Golang还是C#, struct都是一个值类型。
struct 结构体
C#的结构struct
1. 构造函数
struct有默认无参构造函数,不能再显式定义这个无参构造函数,编译器始终会生成一个默认的构造器
结构不能包含显式的无参数构造函数,默认构造器会把所有字段的自动初始化
public struct Position
{
//public Position()
//{} // 这是不允许的
public double Lon { get; set; }
public double Lat { get; set; }
}
//没有自定义构造函数,可不使用new
Position positon;
positon.Lon = 39.26;
positon.Lat = 115.25;
- 自定义的有参构造函数必须初始化所有的字段
public struct Position
{
//自定义构造函数需要初始化所有字段、属性
public Position(double lon, double lat)
{
Lon = lon;
Lat = lat;
}
//结构中不能实例属性或字段初始值设定项
//public double Lon { get; set; }=5.5;
public double Lon { get; set; }
public double Lat { get; set; }
}
//有参构造函数,必须使用new为struct类型的变量赋值
Position positon = new Position(39.26, 39.26);
2. 方法
结构是可以包含自己的方法。
public struct Position
{
//自定义构造函数需要初始化所有字段、属性
public Position(double lon, double lat)
{
Lon = lon;
}
//结构中不能实例属性或字段初始值设定项
//public double Lon { get; set; }=5.5;
public double Lon { get; set; }
public double Lat { get; set; }
//重写方法
public override string ToString() => $"经度:{Lon}, 纬度{Lat})";
}
虽然struct在实际开发过程中使用频率较低,但是使用时需要注意:
- 将结构类型变量作为参数传递给方法或从方法返回结构类型值时,将复制结构类型的整个实例。这可能会影响高性能方案中涉及大型结构类型的代码的性能。通过按引用传递结构类型变量,可以避免值复制操作。使用
ref、out或in方法参数修饰符,指示必须按引用传递参数。使用ref返回值按引用返回方法结果。在Golang中也会存在这个问题,下一节会提到。
Golang的结构体struct
1. 定义
像定义函数类型那样 type开头,只是把func()换为关键字struct
type person struct {
name string
age int8
}
//结构体匿名字段
type student struct {
string
int
}
func main() {
var p1 person
p1.name = "RandyField"
p1.age = 28
//匿名结构体
var user struct {
Name string
Age int
}
user.Name = "Randy"
user.Age = 18
}
2.2* 结构体指针--重点
2.2.1 new
只要是指针,都可以用new()来进行分配内存地址,以达到初始化的目的:
type person struct {
name string
age int8
}
//结构体匿名字段
/*
这里匿名字段的说法并不代表没有字段名,
而是默认会采用类型名作为字段名,
结构体要求字段名称必须唯一,
因此一个结构体中同种类型的匿名字段只能有一个。
*/
type Student struct {
string
int
}
func main() {
//new分配结构体实例的指针(内存地址) 实例化
var p2 = new(person)
fmt.Printf("the type of p2 is %T\n", p2) //*main.person
//没有初始化的结构体 所有的成员变量都是对应类型的零值
fmt.Printf("p2=%#v\n", p2)
stu := &Student{}
stu.int = 18
stu.string = "中学生"
}
the type of p2 is *main.person
p2=&main.person{name:"", age:0}
2.2.2 &取地址符号
这个看起来比new()方便
type person struct {
name string
age int8
}
func main() {
p3 := &person{} //使用&对结构体进行取地址操作=> 使用new实例化
p3.name = "kobe"
p3.age = 30 //这是语法糖
(*p3).age = 29 //其实底层是这样的
}
- 初始化
当某些字段没有初始值的时候,该字段可以不写。此时,没有指定初始值的字段的值就是该字段类型的零值。这点跟C#存在有参构造函数的结构是不一致。
func main() {
p4 := person{
name: "RandyField",
age: 18,
}
fmt.Printf("p4=%#v\n", p4)
//结构体指针初始化
p5 := &person{
name: "RandyField",
age: 28,
}
fmt.Printf("p5=%#v\n", p5)
}
- 另类初始化
不建议使用,但是为了能看懂别人的开源代码,还是知道机制为妙。
p6 := &person{
"RandyField",
28,
}
fmt.Printf("p6=%#v\n", p6)
2.3* 空结构体
特殊地:空结构体是不占用空间的。
var v struct{}
fmt.Println(unsafe.Sizeof(v)) // 0
2.4 构造函数
Golang是没有构造函数的,但是我们可以通过方法去创建一个,返回struct类型。复杂的结构体,值拷贝性能开销会比较大,故返回结构体指针。
type person struct {
name string
age int8
}
// 复杂的结构体,值拷贝性能开销会比较大,故返回结构体指针。
func newPerson(name string, age int8) *person {
return &person{
name: name,
age: age,
}
}
2.5 方法
Golang结构体的方法并不像C#的结构那样直接就在结构的{}中定义即可。它必须分开定义,这就出现一个问题,定义的这个方法是属于这个结构体的,并不希望其他地方都能使用这个方法,但是又必须分开定义,怎么办?
接收者应运而生,指明这个方法是属于结构体,只能通过结构体来调用。
func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}
type person struct {
name string
age int8
}
func (p *person) MakeMoney(work string) (res string) {
return "赚钱了"
}
- 接收者既可以是指针类型,也可以是值类型
- 值类型,如果做出了操作,只针对副本有效
使用指针类型场景:
- 需要修改接收者中的值
- 接收者是拷贝代价比较大的大对象
- 如果有某个方法使用了指针类型接收者,其他的方法也应该使用指针类型接收者。
2.5.1 类型定义 与 类型别名
方法的接收者不仅仅可以是结构体,还可以是类型定义:
type NewInt int //类型定义 新类型 可以作为方法的接收者
type MyInt = int //类型别名 编译完成时并不会有`MyInt`类型, 这个不能作为方法接收者的
func (m NewInt) Say() {
fmt.Println("我其实是int。")
}
- 类型定义 创造一种新类型
- 类型别名,编译后不存在
2.6 嵌套结构体
type student struct {
name string
age int
}
type middleSchoolStudent struct {
lesson []string
*student
}
func (stu *student) play(sport []string) {
for _, v := range sport {
fmt.Println(stu.name, "参加如下运行项目:", v)
}
}
func (m *middleSchoolStudent) learn() {
for _, v := range m.lesson {
fmt.Println(m.name, "学习如下课程:", v)
}
}
func main(){
s := &middleSchoolStudent{
lesson: []string{"语文", "数学", "英语", "物理", "化学"},
student: &student{
name: "小明",
age: 13,
},
}
s.learn()
s.play([]string{"篮球", "足球", "乒乓球"})
}
小明 学习如下课程: 语文
小明 学习如下课程: 数学
小明 学习如下课程: 英语
小明 学习如下课程: 物理
小明 学习如下课程: 化学
小明 参加如下运行项目: 篮球
小明 参加如下运行项目: 足球
小明 参加如下运行项目: 乒乓球
有点像继承,其实这又是一个语法糖:
s.play([]string{"篮球", "足球", "乒乓球"})- 内部是
s.student.play([]string{"篮球", "足球", "乒乓球"})
- 内部是
如果在定义时,给嵌套结构体一个字段名称:
type middleSchoolStudent struct {
lesson []string
stu *student
}
调用方式必须为:s.stu.play([]string{"篮球", "足球", "乒乓球"})
2.7 Tag
Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:
`key1:"value1" key2:"value2"`
type MiddleSchoolStudent struct {
Lesson []string
Name string `json:"studentName"`
Age int `json:"studentAge"`
}
func main(){
ms := &MiddleSchoolStudent{
Name: "小明",
Age: 13,
Lesson: []string{"语文", "数学", "英语", "物理", "化学"},
}
data, err := json.Marshal(ms)
if err != nil {
fmt.Println("json marshal failed")
return
}
fmt.Printf("json:%s\n", data)
// fmt.Println(data)
}
json:{"Lesson":["语文","数学","英语","物理","化学"],"studentName":"小明","studentAge":13}
注意事项: 为结构体编写
Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在key和value之间添加空格。
再次强调:这个系列并不是教程,如果想系统的学习,博主可推荐学习资源。
边栏推荐
- RStudio 1.4软件安装包和安装教程
- 想开个户,在股票网上开户安全吗?资金会被骗走吗?
- What are the requirements for new bonds? Is it safe to play new bonds
- 为什么你的数据图谱分析图上只显示一个值?
- Goldfish rhca memoirs: do447 managing user and team access -- effectively managing users with teams
- ZABBIX monitoring - Aruba AP operation data
- Real topic of the 13th National Competition of single chip microcomputer in the Blue Bridge Cup
- Stochastic process -- Markov chain
- GL Studio 5 installation and experience
- 打新债好不好 打新债安全吗
猜你喜欢

Application of JDBC in performance test

科班出身,结果外包都不要

Check four WiFi encryption standards: WEP, WPA, WPA2 and WPA3

UST 崩盘后,稳定币市场格局将迎来新机遇?

增加双因素认证,不惧密码泄露,更不惧123456

Elastricearch's fragmentation principle of the second bullet

Flagai Feizhi: AI basic model open source project, which supports one click call of OPT and other models

Helix QAC is updated to 2022.1 and will continue to provide high standard compliance coverage

Open source SPL redefines OLAP server

GL Studio 5 安装与体验
随机推荐
打新债有何要求 打新债安全吗
直播分享| 腾讯云 MongoDB 智能诊断及性能优化实践
Development notes of wedding studio applet based on wechat applet
八大误区,逐个击破(终篇):云难以扩展、定制性差,还会让管理员失去控制权?
测试的重要性及目的
活动报名 | MongoDB 5.0 时序存储特性介绍
RStudio 1.4软件安装包和安装教程
Hardware development notes (6): basic process of hardware development, making a USB to RS232 module (5): creating USB package library and associating principle graphic devices
Hotline salon issue 26 - cloud security session
UGeek大咖说 | 可观测之超融合存储系统的应用与设计
准备好迁移上云了?请收下这份迁移步骤清单
好用的人事管理软件有哪些?人事管理系统软件排名!
Robust extraction of specific signals with time structure (Part 2)
Importance and purpose of test
Daily question brushing record (II)
Is it safe to pay new debts
LeetCode 473. Match to square
Gaussdb (DWS) database intelligent monitoring operation and maintenance service - node monitoring indicators
打新债需要具备什么条件 打新债安全吗
Elastricearch's fragmentation principle of the second bullet