目录

  • golang结构体定义
  • 结构体的访问属性
  • 结构体的初始化、赋值
    • 方式1:
    • 方式2:
    • 方式3:
    • 方式4:
    • 全部代码
  • 匿名结构体
  • 结构体的匿名字段
  • 结构体的构造函数
    • 构造函数
    • 指针构造与对象构造
  • 给结构体添加方法
  • 结构体是值类型
  • 结构体做结构体的类型成员
  • 结构体内存布局与字节对齐问题
    • 内存字节对齐
    • 结构体大小
  • 空结构体
  • 结构体切片成员的传值问题

golang结构体定义

go语言的结构体定义需要使用关键字type, 格式如下

type 结构体名 struct{成员1 类型成员2 类型。。。。。。
}

例如下面定义一个Person结构体

//定义结构体
type Person struct {name   stringage    intgender stringhobby  []string
}

结构体的访问属性

结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。

结构体的初始化、赋值

结构体的初始化、赋值大概有四种方式,

方式1:

//结构体定义方法 1
var p Person
p.name = "zhangsan"
p.age = 20
p.gender = "男"
p.hobby = []string{"篮球", "皮球", "双色球"}//打印结构体内容
fmt.Println(p)//访问字段
fmt.Println(p.name)

访问字段直接用结构体变量点出来即可

方式2:

//结构体定义方法 2
//new结构体
p2 := new(Person)
p2.age = 30
p2.name = "zhaoliu"
fmt.Printf("p2 type=%T \n", p2)
fmt.Printf("p2=%p \n", p2)

方式3:

//结构体定义方法 3
//声明时进行初始化
//注意需要使用逗号
p3 := Person{name: "tianqi",age:  17,
}
fmt.Println("p3=", p3)

方式4:

//结构体定义方法 4
//值列表初始化
//必须严格按照结构体里成员的顺序, 这种需要把所有字段都进行赋值,不然无法编译
p4 := Person{"zhangwuji",20,"男",[]string{"乾坤大挪移", "九阳神功", "太极拳"},
}
fmt.Println("p4=", p4)

全部代码

package main
import "fmt"//定义结构体
type Person struct {name   stringage    intgender stringhobby  []string
}func main() {//结构体定义方法 1var p Personp.name = "zhangsan"p.age = 20p.gender = "男"p.hobby = []string{"篮球", "皮球", "双色球"}//打印结构体内容fmt.Println(p)//访问字段fmt.Println(p.name)//结构体定义方法 2//new结构体p2 := new(Person)p2.age = 30p2.name = "zhaoliu"fmt.Printf("p2 type=%T \n", p2)fmt.Printf("p2=%p \n", p2)//结构体定义方法 3//声明时进行初始化//注意需要使用逗号p3 := Person{name: "tianqi",age:  17,}fmt.Println("p3=", p3)//结构体定义方法 4//值列表初始化//必须严格按照结构体里成员的顺序, 这种需要把所有字段都进行赋值,不然无法编译p4 := Person{"zhangwuji",20,"男",[]string{"乾坤大挪移", "九阳神功", "太极拳"},}fmt.Println("p4=", p4)//匿名结构体//不需要名字var s struct {x inty int}s.x = 100s.y = 100// 打印结构体值用%vfmt.Printf("s type = %T, s vale %v", s, s)
}

匿名结构体

可以在函数里直接定义结构体类型,不需要使用type关键字,这种称为匿名结构体.

//匿名结构体
//不需要名字
var s struct {x inty int
}
s.x = 100
s.y = 100
// 打印结构体值用%v
fmt.Printf("s type = %T, s vale %v", s, s)

结构体的匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。

//Person 结构体
type Person struct {stringint
}func main() {p1 := Person{"小王子",18,}fmt.Printf("%#v\n", p1)        //main.Person{string:"北京", int:18}fmt.Println(p1.string, p1.int) //北京 18
}

注意:这里匿名字段的说法并不代表没有字段名,而是默认会采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。

结构体的构造函数

go语言没有像C++、java、c#这种面向对象的特性,在结构体里只能声明变量,不能声明方法,为了构造结构体更方便,可以在同一个包的外面给结构体声明方法,例如可以写构造函数:

package main
import "fmt"type Student struct {id   intname string
}func newStudent(_id int, _name string) Student {return Student{_id, _name,}
}func newStudentPtr(_id int, _name string) *Student {return &Student{_id, _name,}
}//给结构体添加方法
func (this Student) sayHello() {fmt.Printf("我的名字是%s, 学号%d\n", this.name, this.id)
}//值接收
func (this Student) changeId() {this.id++
}//指针接收者
func (this *Student) changeIdYes() {this.id++
}func main() {p1 := newStudent(1001, "张三")fmt.Println(p1)p1.sayHello()p1.changeId()fmt.Printf("id = %d\n", p1.id)p1.changeIdYes()fmt.Printf("id = %d\n", p1.id)p2 := newStudentPtr(1002, "李四")fmt.Println(p2)
}

例如上面的代码,声明了一个Student结构体,newStudent, newStudentPtr是两个构造函数,go语言没有方法重载的概念,所以不能有同名函数。

构造函数

func newStudent(_id int, _name string) Student {return Student{_id, _name,}
}func newStudentPtr(_id int, _name string) *Student {return &Student{_id, _name,}
}

指针构造与对象构造

当结构体成员比较多时,建议使用返回指针的形式进行构造,减少内存的开销,也就是newStudentPtr这种写法;当结构体成员比较少时,可以使用返回对象的写法,也就是newStudent这种写法。

给结构体添加方法

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。
格式如下

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {函数体
}

在上面的代码中,给结构体添加了3个方法

//给结构体添加方法
func (this Student) sayHello() {fmt.Printf("我的名字是%s, 学号%d\n", this.name, this.id)
}//值接收
func (this Student) changeId() {this.id++
}//指针接收者
func (this *Student) changeIdYes() {this.id++
}

注意上面的this可以随便命名,只要是合理的标识符即可,用this,主要是参考C++的写法,更形象,也可以写成self。

结构体是值类型

在方法changeId中,给id成员执行++操作,但是执行后并没有++, 如果想要用方法改变传入的值,得用指针传参,也就是changeIdYes()这种写法

结构体做结构体的类型成员

package main
import "fmt"type BaseInfo struct {id   intname string
}type Student struct {gender stringbaInfo BaseInfo
}
func main() {var s1 Students1.baInfo.name = "张三"s1.baInfo.id = 1001s1.gender = "男"fmt.Println(s1)
}

上面代码是把BaseInfo作为Student的成员
变量名baInfo 也可以不写,例如

package main
import "fmt"type BaseInfo struct {id   intname string
}//type Student struct {// gender string
// baInfo BaseInfo
//}type Student struct {gender stringBaseInfo
}func main() {//var s1 Student//s1.baInfo.name = "张三"//s1.baInfo.id = 1001//s1.gender = "男"var s1 Students1.name = "张三"s1.id = 1001s1.gender = "男"fmt.Println(s1)
}

省略baInfo后,就可以用s1直接访问
这种嵌套定义有点类似C++、java的类继承,不过由于golang的特点,看起来不是那么明显

结构体内存布局与字节对齐问题

go结构体有类似C/C++的内存对齐问题,例如下面的代码

package main
import "fmt"type test struct {a int8b int8c int8d int8
}func main() {n := test{1, 2, 3, 4,}fmt.Printf("n.a %p\n", &n.a)fmt.Printf("n.b %p\n", &n.b)fmt.Printf("n.c %p\n", &n.c)fmt.Printf("n.d %p\n", &n.d)
}

输出
n.a 0xc000128058
n.b 0xc000128059
n.c 0xc00012805a
n.d 0xc00012805b

内存字节对齐

由于是int8,站一个字节,所以此时a,b,c,d的顺序是一致的,如果换成int32就不同了,如下所示

type test struct {a int8b int32c int8d int32
}

输出结果
n.a 0xc00001a0b0
n.b 0xc00001a0b4
n.c 0xc00001a0b8
n.d 0xc00001a0bc
由于要处理内存对齐问题,虽然a是8位,占一个字节,但是它的下一个成员b是占4个字节,为了字节对齐,那么a也是得占用4个字节,c, d类似,如下图:

结构体大小

fmt.Printf("结构体大小:%d", unsafe.Sizeof(n))

例如如上面结构体大小为16
n.a 0xc0000aa070
n.b 0xc0000aa074
n.c 0xc0000aa078
n.d 0xc0000aa07c
结构体大小:16

空结构体

空结构体是不占用空间的。

var v struct{}
fmt.Println(unsafe.Sizeof(v))  // 0

结构体切片成员的传值问题

看下面的代码

package main
import "fmt"type Person struct {name   stringage    int8dreams []string
}func (p *Person) SetDreams(dreams []string) {p.dreams = dreams
}func main() {p1 := Person{name: "小王子", age: 18}data := []string{"吃饭", "睡觉", "打豆豆"}p1.SetDreams(data)fmt.Println(p1.dreams)// 突然修改了data[1]的值data[1] = "不睡觉"fmt.Println(p1.dreams)
}

在设置Person的成员dreams后,不小心修改了slice的值,因为slice类型包含了指向底层数据的指针,此时Person的成员dreams也会被跟着修改
输出结果
[吃饭 睡觉 打豆豆]
[吃饭 不睡觉 打豆豆]
为了避免这种情况,正确的做法是在方法中使用传入的slice的拷贝进行结构体赋值。

func (p *Person) SetDreams(dreams []string) {p.dreams = make([]string, len(dreams))copy(p.dreams, dreams)
}

这种问题存在于slice和map,在实际编码过程中一定要注意这个问题。

go语言结构体详解与代码演示相关推荐

  1. C语言结构体详解(结构体定义,使用,结构体大小等)

    c语言结构体详解 1.c语言结构体 1.1 结构体基础知识 1.2 结构体声明 1.3 结构体特殊声明 1.4 结构体的自引用 1.5 结构体的大小的计算 1.5.1了解结构体大小计算规则 1.5.2 ...

  2. 计算机科学类专升本复习之“C语言结构体”详解(初稿)

    C语言结构体详解,C语言struct用法详解 前面所学到的"数组":它是一组具有"相同类型"的数据的集合. 但是在实际的编程中,我们往往还需要 一组" ...

  3. linux中c语言结构体详解,Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

  4. 梦开始的地方 —— C语言结构体详解

    文章目录 结构体 1. 结构体声明 2. 结构体的自引用 3. 结构体初始化和访问 4. 结构体成员访问 5. 结构体传参 6. 结构体内存对齐 7. 修改默认对齐数 8. 为什么存在结构体内存对齐? ...

  5. C语言 | 结构体详解(C结构体)

    ========================================== 博主github:https://github.com/MichaelBeechan 博主CSDN:https:/ ...

  6. c语言结构体详解(struct)

    在C语言中,可以使用结构体(Struct)来存放一组不同类型的数据.结构体的定义形式为:: struct 结构体名{ 结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数组,它们 ...

  7. 让你不再害怕结构体-C语言结构体详解

    结构体:是一种复合数据类型,多种数据类型集合在一起用来描述事物的整体 与数组类似,数组是都个相同类型的数据合在一起,而结构是多个不同类型的数据合在一起. 结构体归根结底是一种数据类型,由程序员根据需要 ...

  8. C# 之 结构体详解

    C# 之 结构体详解 一.结构体的定义 二.结构体的初始化 1.实例构造函数 2.静态构造函数 三.结构体的使用 1.赋值操作 2.作为方法参数和返回值 一.结构体的定义 概念:C#的结构体类型(或称 ...

  9. 【FFmpeg】结构体详解(二):AVStream、AVPacket、AVOutputFormat

    FFmpeg结构体详解 7.AVStream 8.AVPacket 9.AVOutputFormat 7.AVStream AVStream 是存储每一个视频/音频流信息的结构体. 重要的变量如下所示 ...

最新文章

  1. l298n电机驱动模块_带DRV8825驱动器模块和Arduino的控制步进电机
  2. Flask项目--爱家租房项目结构图
  3. 厉害了,Spring中bean的12种定义方法!
  4. vue 项目上传到码云 解决push失败
  5. 官方晒一加8系列旗舰关键配置:号称更极致的屏幕机皇
  6. IOCP编程小结(中)
  7. [HNOI2008]水平可见直线 半平面交
  8. vscode 翻译_前端新手 VSCode 入门指南
  9. java字符串型断言消息_Java断言
  10. Aizu0189 Convenient Location【Floyd算法】
  11. php 循环获取分类,PHP 循环删除无限分类子节点
  12. 通达OA的一些资源地址,持续更新
  13. NOI / 2.5基本算法之搜索7834:分成互质组(详细讲解)
  14. 2022 美亚杯 资格赛 赛后复盘 题解
  15. Mask RCNN 算法 No Instances to display
  16. [EXCEL] 宏的录制、调用和删除
  17. numpy中数据不以科学记数法显示
  18. golang最适合(擅长)做什么
  19. python大数据工程师 培训_大数据工程师需要学习哪些?
  20. 19级赵同学推荐的十佳医疗图像处理论文

热门文章

  1. Java七大设计原则详解与运用
  2. NUIST第一届程序设计大赛团队赛题解
  3. 献给曾经爱过和正在爱的你
  4. 敏捷的诺基亚测试(Nokia Test)
  5. 在Unity中制作逼真的建筑场景
  6. 聚类算法之高斯混合模型
  7. 大数据技术之_11_HBase学习_03_HBase 实战之谷粒微博(练习API) + 扩展知识(布隆过滤器+HBase2.0 新特性)
  8. Android Studio 通过wify连接手机调试
  9. ASRT语音识别项目
  10. 手把手教你安装WordPress详细教程(图文)