当前位置:网站首页>【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之间添加空格。
再次强调:这个系列并不是教程,如果想系统的学习,博主可推荐学习资源。
边栏推荐
- Is it safe to make new debt
- 解读2022年度敏捷教练行业现状报告
- Gaussdb (DWS) database intelligent monitoring operation and maintenance service - node monitoring indicators
- Stochastic process -- Markov chain
- 打新债有何要求 打新债安全吗
- What are the useful personnel management software? Personnel management system software ranking!
- Save: software analysis, verification and test platform
- 【Golang】跟着源码学技巧系列之对象池sync.Pool
- 「开源摘星计划」Containerd拉取Harbor中的私有镜像,云原生进阶必备技能
- Naacl 2022 finds | byte proposes MTG: multilingual text generation data set
猜你喜欢

准备好迁移上云了?请收下这份迁移步骤清单

Can the biggest gamefi crash victim survive the bear market in May| May Monthly Report

混沌工程,了解一下

直播回顾 | 云原生混部系统 Koordinator 架构详解(附完整PPT)

80% of people will be wrong about the three counter intuitive questions?

墨天轮访谈 | IvorySQL王志斌—IvorySQL,一个基于PostgreSQL的兼容Oracle的开源数据库

The "open source star picking program" container pulls private images from harbor, which is a necessary skill for cloud native advanced technology

Summary of accelerating mobile applications at network edge with software programmable FPGA

Zabbix监控- Aruba AP运行数据

Syntaxe des requêtes fédérées SQL (inline, left, right, full)
随机推荐
What conditions do you need to meet to fight new debts? Is it safe to fight new debts
How to avoid the "black swan" incident in the gene field: a security war behind a preventive "recall"
Eight misunderstandings, broken one by one (final): the cloud is difficult to expand, the customization is poor, and the administrator will lose control?
Is it safe to pay new debts
混沌工程,了解一下
技术分享| WVP+ZLMediaKit实现摄像头GB28181推流播放
墨天轮访谈 | IvorySQL王志斌—IvorySQL,一个基于PostgreSQL的兼容Oracle的开源数据库
How to write a great online user manual in 7 steps
金九银十,靠这个细节,offer拿到手软!
Chaos engineering, learn about it
The golden nine silver ten, depends on this detail, the offer obtains the soft hand!
重庆 奉节耀奎塔,建成后当地连中五名进士,是川江航运的安全塔
国元期货交易软件正规吗?如何安全下载?
Can the biggest gamefi crash victim survive the bear market in May| May Monthly Report
Application of JDBC in performance test
Online text entity extraction capability helps applications analyze massive text data
打新债需要具备什么条件 打新债安全吗
20 provinces and cities announce the road map of the meta universe
1、 Summary and introduction
Summary of accelerating mobile applications at network edge with software programmable FPGA