Golang面向对象编程(一)

文章目录

  • 结构体
    • 基本介绍
    • 结构体定义方式
    • 创建结构体变量
    • 结构体内存对齐
    • 结构体类型转换
    • 字段的Tag标签
  • 方法
    • 基本介绍
    • 方法的定义和调用
    • 方法调用的传参机制
    • String方法

结构体

基本介绍

基本介绍

  • Go支持面向对象编程特性,包括封装、继承和多态,但Go中没有类(class)而是基于结构体(struct)来实现OOP特性的。
  • 结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体,结构体中的成员称为结构体的字段。
  • 在编程过程中,通常将一类事物的特性提取出来,形成一个结构体类型,然后基于这个结构体类型创建出多个实例。

结构体定义方式

结构体定义方式

Go中结构体定义的基本语法如下:

在这里插入图片描述

使用案例如下:

// 定义结构体
type Student struct {Name   stringAge    intGender string
}

结构体是值类型,不同结构体变量的字段是独立的,互不影响。如下:

在这里插入图片描述

说明一下:

  • 结构体中字段的类型可以是任意类型,包括基本数据类型、数组、引用类型以及自定义类型。

创建结构体变量

创建结构体变量

方式一: 指明结构体的类型,结构体字段采用对应的默认值。

var stu1 Student
fmt.Printf("stu1 = %v\n", stu1)      // stu1 = { 0 }
fmt.Printf("stu1 type = %T\n", stu1) // stu1 type = main.Student

方式二: 指明结构体的类型,并初始化结构体字段。

var stu2 = Student{"Alice", 12, "女"}
fmt.Printf("stu2 = %v\n", stu2)      // stu2 = {Alice 12 女}
fmt.Printf("stu2 type = %T\n", stu2) // stu2 type = main.Student

方式三: 指明结构体的类型,并通过字段名的方式初始化结构体字段。

var stu3 = Student{Name:   "Alice",Age:    12,Gender: "女",
}
fmt.Printf("stu3 = %v\n", stu3)      // stu3 = {Alice 12 女}
fmt.Printf("stu3 type = %T\n", stu3) // stu3 type = main.Student

方式四: 通过new函数创建指定类型的结构体变量,得到指向结构体变量的指针。

var stu4 = new(Student)
fmt.Printf("stu4 = %v\n", stu4)      // stu4 = &{ 0 }
fmt.Printf("stu4 type = %T\n", stu4) // stu4 type = *main.Student

方式五: 指明结构体的类型,并初始化结构体字段,得到指向结构体变量的指针。

var stu5 = &Student{"Alice", 12, "女"}
fmt.Printf("stu5 = %v\n", stu5)      // stu5 = &{Alice 12 女}
fmt.Printf("stu5 type = %T\n", stu5) // stu5 type = *main.Student

方式六: 指明结构体的类型,并通过字段名的方式初始化结构体字段,得到指向结构体变量的指针。

var stu6 = &Student{Name:   "Alice",Age:    12,Gender: "女",
}
fmt.Printf("stu6 = %v\n", stu6)      // stu6 = &{Alice 12 女}
fmt.Printf("stu6 type = %T\n", stu6) // stu6 type = *main.Student

说明一下:

  • 在创建结构体变量并初始化结构体字段时,如果通过字段名的方式对结构体字段进行初始化,那么可以不需要对所有字段都进行初始化,没有初始化的字段将会采用对应的默认值,否则需要对结构体所有字段进行初始化,并且初始化的顺序必须与结构体字段的定义顺序相同。

结构体内存对齐

结构体内存对齐规则

Go中结构体的大小遵循结构体的对齐规则:

  1. 结构体中第一个字段,对齐到结构体的首地址处。
  2. 结构体中的其他字段,对齐到各自对齐数的整数倍的地址处。
  3. 结构体的总大小为最大对齐数(每个字段都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体,嵌套结构体对齐到自己的最大对齐数的整数倍处。

其中,不同类型字段的对齐数可能不同,通过unsafe包中的Alignof函数可以获取指定类型对应的对齐数。

结构体大小计算案例

下面代码中分别获取了Student结构体中各个字段的对齐数和大小。如下:

package mainimport ("fmt""unsafe"
)type Student struct {Name   stringAge    uint8Gender string
}func main() {var stu = Student{"Alice", 12, "女"}fmt.Printf("Name align number = %d\n", unsafe.Alignof(stu.Name))     // Name align number = 8fmt.Printf("Name size = %d\n", unsafe.Sizeof(stu.Name))              // Name size = 16fmt.Printf("Age align number = %d\n", unsafe.Alignof(stu.Age))       // Age align number = 8fmt.Printf("Age size = %d\n", unsafe.Sizeof(stu.Age))                // Age size = 1fmt.Printf("Gender align number = %d\n", unsafe.Alignof(stu.Gender)) // Gender align number = 8fmt.Printf("Gender size = %d\n", unsafe.Sizeof(stu.Gender))          // Gender size = 16fmt.Printf("stu align number = %d\n", unsafe.Alignof(stu))           // stu align number = 8fmt.Printf("stu size = %d\n", unsafe.Sizeof(stu))                    // stu size = 40
}

上述结构体变量在内存中的布局如下:

在这里插入图片描述

说明一下:

  • 图中的内存以字节为单位进行划分,内存旁边的小标号,表示当前位置相对于结构体起始位置的偏移量。
  • Name作为结构体中的第一个字段,对齐到结构体的首地址处,图中黄色部分表示Name字段占用的内存,共16字节。
  • Age字段对齐到8的整数倍处,图中粉红色部分表示Age字段占用的内存,共1字节。
  • Gender字段对齐到8的整数倍处,图中蓝色部分表示Gender字段占用的内存,共16字节。
  • 结构体的总大小为最大对齐数的整数倍,即8的整数倍,所以该结构体的大小为40字节。

结构体类型转换

结构体类型转换

Go中的结构体类型是自定义类型,自定义类型之间可以进行类型转换,但要求这两个自定义类型拥有完全相同的字段名、字段个数和字段类型,并且字段的声明顺序也必须相同。如下:

package mainimport "fmt"type Student struct {Name   stringAge    intGender string
}type Person struct {Name   stringAge    intGender string
}func main() {var per = Person{"Alice", 12, "女"}var stu Student = Student(per) // 类型转换fmt.Printf("stu = %v\n", stu)  // stu = {Alice 12 女}
}

Go中可以通过type给自定义类型取别名,但编译器会认为这是一个新的数据类型,在相互赋值时需要进行类型转换,无法直接赋值。如下:

package mainimport "fmt"type Student struct {Name   stringAge    intGender string
}type Stu Studentfunc main() {var student = Student{"Alice", 12, "女"}var stu Stu = Stu(student)    // 类型转换fmt.Printf("stu = %v\n", stu) // stu = {Alice 12 女}
}

字段的Tag标签

字段的Tag标签

在定义结构体时,可以在每个结构体字段的后面设置tag标签,并用反引号将其包裹起来。tag标签可以用于存储与字段相关的信息,例如数据库列名、JSON序列化配置、表单验证等。如下:

package mainimport ("encoding/json""fmt"
)type Student struct {Name   string `json:"name"`Age    int    `json:"age"`Gender string `json:"gender"`
}func main() {// json序列化var stu1 = Student{"Alice", 12, "女"}data, err := json.Marshal(stu1)if err != nil {fmt.Printf("json serialize error, err = %v\n", err)return}fmt.Printf("json string = %v\n", string(data)) // json string = {"name":"Alice","age":12,"gender":"女"}// json反序列var stu2 Studentfmt.Printf("stu2 = %v\n", stu2) // stu2 = { 0 }err = json.Unmarshal(data, &stu2)if err != nil {fmt.Printf("json unserialize error, err = %v\n", err)return}fmt.Printf("stu2 = %v\n", stu2) // stu2 = {Alice 12 女}
}

说明一下:

  • 标签的一般形式是key:"value",其中key表示标签的名称,value表示与该标签相关的值,多个标签可以用空格分隔,通过Go中的反射机制可以获取标签的信息。
  • 上述代码中通过字段标签,分别指定了结构体各个字段在JSON序列化时的名称,可以看到序列化后的JSON字符串中使用的字段名称就是标签中指定的名称,如果没有指定那么在JSON序列化时会默认使用字段名。
  • Marshal是encoding/json包中的函数,用于进行JSON序列化,该函数接收任意类型的参数,如果序列化成功,则序列化后的JSON字符串通过第一个返回值返回,如果序列化失败,则会通过第二个返回值返回错误原因。
  • Unmarshal是encoding/json包中的函数,用于进行JSON反序列化,该函数接收两个参数,第一个参数是待反序列化的字符串,第二个参数作为输出型参数接收反序列化的结果,如果反序列化失败,则通过返回值返回错误原因。
  • Marshal函数进行JSON序列化时,返回的JSON字符串是[]byte类型的,Unmarshal函数在进行JSON反序列化时,要求传入的JSON字符串也是[]byte类型的,在使用时注意进行类型转换。

方法

基本介绍

基本介绍

  • Go中的方法指的是与特定类型关联的函数,它们为类型提供了行为和操作方式,并允许类型的实例对这些方法进行调用。
  • Go语言规定方法和类型的定义必须在同一个包中,使得类型与方法紧密耦合在一起,这有助于保持代码的模块化和可读性。此外,将方法与类型定义在同一个包,保证了方法能够访问类型不可导出的字段和方法,并能有效避免其他包对类型的行为进行修改。

方法的定义和调用

方法的定义和调用

Go中方法定义的基本语法如下:

在这里插入图片描述

创建类型的实例后,通过实例.方法名的方式即可调用对应的方法。如下:

package mainimport "fmt"type Student struct {Name   stringAge    intGender string
}func (stu Student) PrintAge() {fmt.Printf("age = %d\n", stu.Age)
}func (stu *Student) AgeAdd() {stu.Age++
}func main() {var stu = Student{"Alice", 12, "女"}stu.AgeAdd()stu.PrintAge() // Alice age = 13
}

说明一下:

  • 上述代码中定义了Student类型,并为该类型定义(绑定)了两个方法,分别是PrintAge和AgeAdd。
  • 在定义方法时,receiver type表示该方法与type类型进行绑定,当通过实例调用方法时会将实例传递给receiver。如果希望在方法中改变实例的值,需要将type设置为对应类型的指针类型。
  • 方法的访问控制与函数相同,方法名首字母小写只能在本包中访问,方法名首字母大写可以在本包和其他包访问。
  • 通过结构体指针访问结构体字段时,Go语言会自动对指针进行解引用操作,因此代码中的stu.Age++等价于(*stu).Age++

方法调用的传参机制

方法调用的传参机制

在Go中,不仅可以通过实例来调用其绑定的方法,通过实例的指针同样能够完成方法的调用。如下:

package mainimport "fmt"type Student struct {Name   stringAge    intGender string
}func (stu Student) PrintAge() {fmt.Printf("%s age = %d\n", stu.Name, stu.Age)
}func (stu *Student) AgeAdd() {stu.Age++
}func main() {// 结构体变量调用方法var stu1 = Student{"Alice", 12, "女"}stu1.AgeAdd()stu1.PrintAge() // Alice age = 13// 结构体指针调用方法var stu2 = &Student{"Bob", 14, "男"}stu2.AgeAdd()stu2.PrintAge() // Bob age = 15
}

说明一下:

  • 通过实例和实例的指针均能完成方法的调用,但在调用方法时,实例具体的传参形式由对应方法的绑定类型决定。
  • 如果被调用方法绑定的是类型,则调用方法时实例以值拷贝的方式传递给方法中的receiver参数;如果被调用方法绑定的是类型的指针,则调用方法时实例以地址拷贝的方式传递给方法中的receiver参数。

String方法

String方法

在Go中,如果一个类型实现了String方法,那么在使用fmt包中的函数打印该类型变量时,就会输出String方法返回的字符串。如下:

package mainimport "fmt"type Student struct {Name   stringAge    intGender string
}func (stu Student) String() string {return fmt.Sprintf("%s是一个%d岁的%s孩\n", stu.Name, stu.Age, stu.Gender)
}func main() {var stu = Student{"Alice", 12, "女"}fmt.Printf("stu = %v\n", stu) // stu = Alice是一个12岁的女孩
}

说明一下:

  • 在使用fmt包中的函数打印变量时,如果该变量类型实现了String方法,那么在打印变量时会通过调用String方法来获取字符串并输出,否则会根据变量的类型进行默认的格式化操作并输出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/9859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux——综合实验

要求 按照上面的架构部署一个简单的web节点所有的服务器使用DNS服务器作为自己的DNS服务器 就是/etc/reslov.conf 中nameserver的值必须是途中dns服务器的地址所有的数据库都是用mysql应用 nfs共享导出在客户端(web服务器上)使用autofs在自动挂载,或者写入/etc/fsta…

window10设置静态IP

右键桌面网络图标 点击属性 点击要查看的网络 点击详细信息 获得网络连接详细信息 右键WiFi符号 或者其他方式进入网络与internet中心 点击 WLAN 点击属性 点击编辑(点击一个即可) 选择手动将刚才的信息方进入即可 完成

MySQL变量的声明与使用

MySQL变量的声明与使用 1、标识符不能以数字开头 2、自能使用_或$符号,不允许使用其他符号。 3、不允许使用系统关键字 将赋值与查询结合 set userName 刘德华; select userName: 刘青云; # 将赋值与查询结合 查询变量/使用变量 select userName as 读取到的u…

TDN: Temporal Difference Networks for Efficient Action Recognition 论文阅读

TDN: Temporal Difference Networks for Efficient Action Recognition 论文阅读 Abstract1. Introduction2. Related work3. Temporal Difference Networks3.1. Overview3.2. Short-term TDM3.3. Long-term TDM3.4. Exemplar: TDN-ResNet 4. ExperimentsAblation studiesCompa…

抖音新店怎么对接达人?对接达人秘籍流程分享,让你学会找达人

大家好,我是电商花花。 新手怎么对接达人带货?这是我们新手商家 要考虑的问题。 很多新手抱怨自己新店铺不出单,没有销量,对接达人又怕达人看不上,没有达人愿意帮我带货,在面临这样的情况下不知道该怎么办…

【科研】常用的实验结果评价指标(1) —— R2(R-square)是什么?

常用的实验结果评价指标(1) —— R2(R-square),可能为负数吗?! 提示:先说概念,后续再陆续上代码 文章目录 常用的实验结果评价指标(1) —— R2(R-square),可能…

ETL免费工具kettle(PDI),安装和配置

起源: Kettle最早是一个开源的ETL工具,全称为KDE Extraction, Transportation, Transformation and Loading Environment。在2006年,Pentaho公司收购了Kettle项目,原Kettle项目发起人Matt Casters加入了Pentaho团队,成…

Redis学习5——Redis应用之签到

Redis位图bitMap 位图由一系列二进制位组成,每个位可以被设置为1或0,当我们在处理需要高效存储和操作大量二进制位数据的适合,位图是一个非常有用的工具。 位图操作命令有: SETBIT:设置位图中指定位置的位的值。可以…

ICode国际青少年编程竞赛- Python-4级训练场-绿色能量1

ICode国际青少年编程竞赛- Python-4级训练场-绿色能量1 1、 Dev.step(3) Dev.turnLeft() Dev.step(3) Spaceship.step(4) Spaceship.turnRight() Spaceship.step(4) Dev.step(3) while Item[1].y ! Dev.y:wait()2、 Dev.step(4) while Item[0].x ! Dev.x:wait() Dev.turnLe…

【SAP ME 38】SAP ME发布WebService配置及应用

更多WebService介绍请参照 【SAP ME 28】SAP ME创建开发组件(DC)webService 致此一个WebService应用发布成功,把wsdl文件提供到第三方系统调用接口! 注意: 在SAP ME官方开发中默认对外开放的接口是WebService接口&am…

(2024,SD,条件 GAN,蒸馏,噪声到图像翻译,E-LatentLPIPS)将扩散模型蒸馏为条件 GAN

Distilling Diffusion Models into Conditional GANs 公和众和号:EDPJ(进 Q 交流群:922230617 或加 VX:CV_EDPJ 进 V 交流群) 目录 0. 摘要 3. 方法 3.1 用于一步生成的配对的噪声到图像翻译 3.2 用于潜在空间蒸馏…

中国接入internet30周年,你的企业“互联网”了吗

所谓数字化就是把生意互联网化,升级官网为营销枢纽:“生意的成功从来都是源于你能被找到和找得到更多客户。” 新时代、新征程,当下,我国也持续推进发展数字经济、促进数字经济和实体经济深度融合,应用新一代数字技术&…

【计算机毕业设计】springboot国风彩妆网站

二十一世纪我们的社会进入了信息时代, 信息管理系统的建立,大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多,而在线管理系统刚好能满足这些需求,在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…

北京车展现场体验商汤DriveAGI自动驾驶大模型展现认知驱动新境界

在2024年北京国际汽车展的舞台上,众多国产车型纷纷亮相,各自展示着独特的魅力。其中,小米SUV7以其精美的外观设计和宽敞的车内空间,吸引了无数目光,成为本届车展上当之无愧的明星。然而,车辆的魅力并不仅限…

mac安装禅道

前提已安装:phpapacheMySQL mac安装 php7.1/apache-CSDN博客 安装MySQL 一、禅道下载 安装官方文档 源码包下载地址:禅道下载 - 禅道开源项目管理软件 。 1. 解压禅道源码包 2. 将解压后的文件复制到Apache访问目录下 (默认路径为 /Libra…

PCIE学习(2)PCIE配置空间详解

文章目录 前言一、配置空间header二、Base Address register(BAR)2.1、BAR是干什么的2.2、具体实现过程BAR示例1——32bit内存地址空间请求BAR示例2——64bit内存地址空间请求 前言 图片来自:https://zhuanlan.zhihu.com/p/463518877 一、…

ubuntu配置多版本cuda+cudnn环境,及版本切换方法

ubuntu配置多版本cudacudnn环境,及版本切换方法 环境如下: ubuntu 22.04cuda v11.8cudnn v8.9.7 文章目录 ubuntu配置多版本cudacudnn环境,及版本切换方法1.安装Nvidia显卡驱动1.1卸载默认的驱动nouveau1.2安装nvidia驱动 2.安装cuda3.安装…

分布式与一致性协议之MySQL XA协议

MySQL XA协议 概述 相信很多人都知道MySQL支持单机事务,那么在分布式系统中,涉及多个节点,MySQL又是怎样实现分布式事务的呢? 举个例子,一个业务系统需要接收来自外部的指令,然后访问多个内部其他系统来执…

Pycharm无法链接服务器环境(host is unresponsived)

困扰了很久的一个问题,一开始是在服务器ubuntu20.04上安装pycharm community,直接运行服务器上的pycharm community就识别不了anaconda中的环境 后来改用pycharm professional也无法远程连接上服务器的环境,识别不了服务器上的环境&#xff…

【Web后端】web后端开发简介_Servlet简介

1.web后端开发简介 Java企业级开发,也就是学习]avaEE(Enterprise Edition)版本,是一种结构和一套标准。在应用中开发的标准就是Servlet、jsp和JavaBean技术。jsp技术现在已基本处于淘汰状态,简单了解即可web后端开发,基于B/S模式的开发体系。…