Go语言结构体(struct)面向对象编程基础篇

news/2024/9/17 1:48:59/文章来源:https://www.cnblogs.com/yinzhengjie/p/18326507

                                              作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

目录
  • 一.面向对象的引入
    • 1.Golang语言面向对象编程
    • 2.结构体的引入
    • 3.结构体定义
    • 4.结构体五种初始化方式
    • 5.结构体的互相转换
    • 6.匿名结构体
  • 二.结构体方法定义
    • 1.方法概述
    • 2.方法是值拷贝传递方式
    • 3.指针类型的接收者
    • 4.为内置数据类型绑定方法
    • 5.结构体的String()方法
    • 6.函数和方法的区别
    • 7.什么时候应该使用指针类型接受者
  • 三.跨包创建结构体实例
    • 1 首字母大写可以支持跨包
      • 1.1 项目测试结构
      • 1.2 创建go.mod文件
      • 1.3 dongman.go
      • 1.4 main.go
      • 1.5 测试代码
    • 2 首字母小写基于工厂模式实现跨包
      • 2.1 项目测试结构
      • 2.2 创建go.mod文件
      • 2.3 dongman.go
      • 2.4 main.go
      • 2.5 测试代码

一.面向对象的引入

1.Golang语言面向对象编程

- 1.Golang也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言,所以我们说Golang支持面向对象编程特性是比较准确的;- 2.Golang中没有类(Class)的概念,Go语言的结构体(struct)和其他编程语言的类有同等的地位,你可以理解Golang是基于struct来实现OOP特性的;- 3.Golang面向对象编程非常简洁,却掉了传统OOP语言的方法重载,构造函数和析构函数,隐藏的this指针等等;- 4.Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继承Golang没有类似于extends关键字,而是通过匿名字段实现;- 5.Golang中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。- 6.Golang中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型。- 7.Golang自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。

2.结构体的引入

package mainimport "fmt"func main() {var (// 描述《仙逆》男主dongman string   = "仙逆"name    string   = "王林"gender  bool     = truehobby   []string = []string{"修炼", "李慕婉", "极镜"}// 描述《凡人修仙传》男主dongman2 string   = "凡人修仙传"name2    string   = "韩立"gender2  bool     = truehobby2   []string = []string{"炼丹", "阵法", "修炼"})/*如果描述一个对象一直使用变量来处理,则会存在以下缺点:- 1.不利于数据的管理和维护;- 2.每个动漫的很多熟悉属于一个对象,用变量管理太分散;综上所述,我们就不得不学习结构体(struct):- 1.Go语言中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了。- 2.Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。 也就是我们可以通过struct来定义自己的类型了。*/fmt.Printf("《%s》name: [%s], gender: [%t], hobby: %v\n", dongman, name, gender, hobby)fmt.Printf("《%s》name: [%s], gender: [%t], hobby: %v\n", dongman2, name2, gender2, hobby2)}

3.结构体定义

package mainimport "fmt"// DongMan 定义动漫结构体,将动漫中各个属性放入一个结构体中管理
type DongMan struct {// 变量名称大写外界可以访问这个属性Name stringAge intGender boolHobby []string
}func main() {// 创建动漫结构体的实例,对象,变量// 描述《仙逆》男主var xianni DongManxianni.Name = "王林"xianni.Gender = truexianni.Hobby = []string{"修炼", "李慕婉", "极镜"}xianni.Age =400// 描述《凡人修仙传》男主var xiuxian DongManxiuxian.Name = "韩立"xiuxian.Gender = truexiuxian.Hobby = []string{"炼丹", "阵法", "修炼"}xiuxian.Age = 217fmt.Printf("《仙逆》: %v\n", xianni)fmt.Printf("《凡人修仙传》: %v\n", xiuxian)
}

4.结构体五种初始化方式

package mainimport "fmt"// DongMan 定义动漫结构体,将动漫中各个属性放入一个结构体中管理
type DongMan struct {// 变量名称大写外界可以访问这个属性Name stringAge intGender boolHobby []string
}func main() {// 实例化方式一: 先定义再赋值var xianni DongManxianni.Name = "王林"xianni.Gender = truexianni.Age = 400xianni.Hobby = []string{"修炼", "李慕婉", "极镜"}fmt.Println(xianni)// 实例化方式二: 按照字段定义顺序初始化赋值,缺点: 必须按照顺序填写且各字段不可省略,有局限性。var xiuxian DongMan = DongMan{"韩立", 217, true, []string{"炼丹", "阵法", "修炼"},}// 实例化方式三: 按照字段名称初始化赋值,即使用键值对初始化,跟顺序无关。var yongSheng DongMan = DongMan{Hobby:  []string{"修炼", "耍酷"},Gender: true,Name:   "方寒",Age:    20,}// 实例化方式四: 通过指针变量赋值, 通过new方法返回初始化变量,得到指针变量var yiNianYongHeng *DongMan = new(DongMan)// "yiNianYongHeng"是指针,其实指向的就是地址,应该给这个地址指向的对象字段赋值,其中"*"的作用就是根据地址取值(*yiNianYongHeng).Name = "白小纯"(*yiNianYongHeng).Age = 50// 为了符合程序员的编程习惯,go提供了简化的赋值方式,go编译器底层对"yiNianYongHeng.Gender"转换为"(*yiNianYongHeng).Gender",这种简写的方式我们称之为"语法糖"yiNianYongHeng.Gender = true yiNianYongHeng.Hobby = []string{"炼丹", "修炼", "整蛊"}// 实例化方式五: 取对象地址值返回指针对象,取结构体的地址实例化。用&对结构体进行取地址操作相当于对该结构体类型进行了一次new实例化操作var tunShiXingKong *DongMan = &DongMan{}(*tunShiXingKong).Name = "罗峰"(*tunShiXingKong).Age = 25tunShiXingKong.Gender = truetunShiXingKong.Hobby = []string{"修炼", "宇宙级精神念师"}fmt.Printf("《仙逆》: %v\n", xianni)fmt.Printf("《凡人修仙传》: %v\n", xiuxian)fmt.Printf("《永生》: %v\n", yongSheng)fmt.Printf("《一念永恒》: %v\n", *yiNianYongHeng)fmt.Printf("《吞噬星空》: %v\n", *tunShiXingKong)}

5.结构体的互相转换

package mainimport "fmt"type Cat struct {Name stringAge  uint8
}type Dog struct {Name stringAge  uint8
}type BaGeQuan Dogfunc main() {var (b BaGeQuan = BaGeQuan{"雨花剑传人神医", 19}c Cat      = Cat{"虹猫", 18}d Dog      = Dog{"逗逗", 17})fmt.Printf("转换前: b = %v\n", b)fmt.Printf("转换前: c = %v\n", c)fmt.Printf("转换前: d = %v\n", d)// 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字,个数和类型)c = Cat(d)// 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是互相间可以强转。d = Dog(b)fmt.Println("----- 分割线 -----")fmt.Printf("转换后: b = %v\n", b)fmt.Printf("转换后: c = %v\n", c)fmt.Printf("转换后: d = %v\n", d)
}

6.匿名结构体

package mainimport ("fmt"
)func main() {// 在定义一些临时数据结构等场景下还可以使用匿名结构体。var user struct {Name stringAge  int}// 使用匿名结构体进行赋值user.Name = "Jason Yin"user.Age = 18fmt.Printf("%#v\n", user)
}

二.结构体方法定义

1.方法概述

Go语言中的方法(Method)是一种作用于特定类型变量的函数,这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者self。方法的定义格式如下:func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {函数体}相关参数说明:接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是self、this之类的命名。例如,Person类型的接收者变量应该命名为p。接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。方法名、参数列表、返回参数:具体格式与函数定义相同。方法使用注意事项:- 1.结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式;- 2.如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来传递;- 3.Golang中的方法作用在指定的数据类型上的,和指定的数据类型绑定,因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32等都可以有方法;- 4.方法的访问控制的规则,和函数一样,方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问;- 5.如果一个类型实现了String()这个方法,那么"fmt.Println"默认会调用这个变量的"String()"方法进行输出;函数和方法的区别如下:- 1.绑定指定类型方法需要绑定指定数据类型,而函数不需要绑定数据类型。- 2.调用方式不一样方法的调用方式为: "对象.方法名称(实参列表)",函数的调用方式为: "函数名(实参列表)"。- 3.传递参数方式不一样对于方法来说,接受者为值类型,可以传入指针类型,接受值为指针类型,可以传入值类型。对于函数来说,参数类型对应是什么就要传入对应的类型。

2.方法是值拷贝传递方式

package mainimport "fmt"// DongMan 定义动漫结构体
type DongMan struct {Name   stringLeader stringAge    uint16
}// 给DongMan结构体绑定SayHi方法,方法名称可以随意起
func (d DongMan) SayHi() {d.Age = 500fmt.Printf("大家好,我是《%s》的男主[%s],[%d]岁达到元婴期境界~\n", d.Name, d.Leader, d.Age)
}func main() {var xianNi DongMan// 结构体对象传入SayHi方法中是值传递,和函数参数传递效果一致xianNi.Name = "仙逆"xianNi.Leader = "王林"xianNi.Age = 407// 结构体DongMan和SayHi方法绑定,调用SayHi方法必须靠指定类型DongMan,如果其他类型调用SayHi一定会报错。xianNi.SayHi()fmt.Printf("xianNi.Age =  %d\n", xianNi.Age)
}

3.指针类型的接收者

package mainimport "fmt"type DongMan struct {Name   stringLeader stringAge    uint16
}func (d DongMan) SayHi() {fmt.Printf("in SayHi ... d的地址: %p, d存储的数据:%p\n", &d, &d)fmt.Printf("大家好,我是《%s》的男主[%s],[%d]岁达到元婴期境界~\n", d.Name, d.Leader, d.Age)
}func (d *DongMan) SetAge(age uint16) {(*d).Age = age // 可简写为"d.Age = age"fmt.Printf("in SetAge ... d的地址: %p, d存储的数据:%p\n", &d, d)
}func main() {var xianNi DongManxianNi.Name = "仙逆"xianNi.Leader = "王林"xianNi.Age = 407fmt.Printf("in main ... xianNi的地址: %p\n", &xianNi)(&xianNi).SetAge(500) // 可简写为“xianNi.SetAge(500)”xianNi.SayHi()fmt.Printf("xianNi.Age =  %d\n", xianNi.Age)
}

4.为内置数据类型绑定方法

package mainimport "fmt"// 定义一个Integer类型,让其作为int的别名,之后就可以为其添加方法
type Integer intfunc (i Integer) SayHi() {fmt.Printf(" i = %d\n", i)
}func (i *Integer) SetInt(number int) {*i = Integer(number)
}func main() {var x Integer = 100x.SayHi()x.SetInt(200)x.SayHi()
}

5.结构体的String()方法

package mainimport "fmt"type DongMan struct {Name   stringLeader stringAge    intHobby  []string
}// 建议大家定义String()作为输出结构体信息的方法,在会"fmt.Println"时自动调用哟~
func (d DongMan) String() string {return fmt.Sprintf("[%s]的男主是[%s],在[%d]岁时修炼到元婴", d.Name, d.Leader, d.Age)
}func main() {var xiuxian DongManxiuxian.Name = "《凡人修仙传》"xiuxian.Leader = "韩立"xiuxian.Hobby = []string{"炼丹", "阵法", "修炼"}xiuxian.Age = 217fmt.Println(xiuxian)}

6.函数和方法的区别

package mainimport "fmt"type DongMan struct {Name string
}// SetName 方法
func (d *DongMan) SetName(name string) {d.Name = name
}// getName 方法
func (d DongMan) getName() {fmt.Printf("in method ... d.Name = %s\n", d.Name)
}// getName 函数
func getName(d DongMan) {fmt.Printf("in function ... d.Name = %s\n", d.Name)
}func main() {var yongSheng DongMan// 调用方法yongSheng.SetName("永生") // 但是不使用指针方式传递依旧可行,// (&yongSheng).SetName("一念永恒") // 正常应该使用指针方式传递// yongSheng.getName()(&yongSheng).getName()    // 虽然用指针类型调用,但是传递还是按照值传递的形式// 调用函数getName(yongSheng)// getName(&yongSheng) // 错误,函数不支持指针变量传递/*综上所述,我们总结函数和方法的区别如下:- 1.绑定指定类型方法需要绑定指定数据类型,而函数不需要绑定数据类型。- 2.调用方式不一样方法的调用方式为: "对象.方法名称(实参列表)",函数的调用方式为: "函数名(实参列表)"。- 3.传递参数方式不一样对于方法来说,接受者为值类型,可以传入指针类型,接受值为指针类型,可以传入值类型。对于函数来说,参数类型对应是什么就要传入对应的类型。*/
}

7.什么时候应该使用指针类型接受者

- 1.需要修改接收者中的值;- 2.接收者是拷贝代价比较大的大对象- 3.保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

三.跨包创建结构体实例

1 首字母大写可以支持跨包

1.1 项目测试结构

如上图所示,本案例仅需要让main包倒入dongman包进行测试即可。

1.2 创建go.mod文件

yinzhengjie@bogon 10-struct-package % go mod init yinzhengjie-dongman
go: creating new go.mod: module yinzhengjie-dongman
yinzhengjie@bogon 10-struct-package % 
yinzhengjie@bogon 10-struct-package % ls
go.mod
yinzhengjie@bogon 10-struct-package % 
yinzhengjie@bogon 10-struct-package % cat go.mod 
module yinzhengjie-dongmango 1.22.4
yinzhengjie@bogon 10-struct-package % 

1.3 dongman.go

package dongmanimport "fmt"type DongMan struct {Name   stringLeader stringAge    intHobby  []string
}func (d DongMan) String() string {return fmt.Sprintf("[%s]的男主是[%s],爱好是: %v,在[%d]岁时修炼到元婴哟~", d.Name, d.Leader, d.Hobby, d.Age)
}

1.4 main.go

package mainimport ("fmt""yinzhengjie-dongman/dongman"
)func main() {var xiuxian dongman.DongManxiuxian.Name = "《凡人修仙传》"xiuxian.Leader = "韩立"xiuxian.Hobby = []string{"炼丹", "阵法", "修炼"}xiuxian.Age = 217fmt.Println(xiuxian)}

1.5 测试代码

yinzhengjie@bogon 10-struct-package % go run main/main.go
[《凡人修仙传》]的男主是[韩立],爱好是: [炼丹 阵法 修炼],在[217]岁时修炼到元婴哟~
yinzhengjie@bogon 10-struct-package % 

2 首字母小写基于工厂模式实现跨包

2.1 项目测试结构

如上图所示,本案例仅需要让main包倒入dongman包进行测试即可。

2.2 创建go.mod文件

yinzhengjie@bogon 11-struct-package-2 % source /etc/profile 
yinzhengjie@bogon 11-struct-package-2 % 
yinzhengjie@bogon 11-struct-package-2 % ls       
yinzhengjie@bogon 11-struct-package-2 % 
yinzhengjie@bogon 11-struct-package-2 % go mod init yinzhengjie-dongman
go: creating new go.mod: module yinzhengjie-dongman
yinzhengjie@bogon 11-struct-package-2 % 
yinzhengjie@bogon 11-struct-package-2 % ls
go.mod
yinzhengjie@bogon 11-struct-package-2 % 
yinzhengjie@bogon 11-struct-package-2 % cat go.mod 
module yinzhengjie-dongmango 1.22.4
yinzhengjie@bogon 11-struct-package-2 % 

2.3 dongman.go

package dongmanimport "fmt"type dongMan struct {Name   stringLeader stringAge    intHobby  []string
}func (d dongMan) String() string {return fmt.Sprintf("[%s]的男主是[%s],爱好是: %v,在[%d]岁时修炼到元婴哟~", d.Name, d.Leader, d.Hobby, d.Age)
}// 工厂模式,调用该方法就会返回"dongMan"的指针类型对象哟~有点类似其他编程语言的"构造方法"
func NewDongMan(name,leader string,age int,hobby []string) *dongMan {return &dongMan{Name: name,Leader: leader,Age: age,Hobby: hobby,}
}

2.4 main.go

package mainimport ("fmt""yinzhengjie-dongman/dongman"
)func main() {xianNi := dongman.NewDongMan("《仙逆》", "王林", 400, []string{"极镜", "阵法", "修炼"})fmt.Println(xianNi)}

2.5 测试代码

yinzhengjie@bogon 11-struct-package-2 % go run main/main.go
[《仙逆》]的男主是[王林],爱好是: [极镜 阵法 修炼],在[400]岁时修炼到元婴哟~
yinzhengjie@bogon 11-struct-package-2 % 

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

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

相关文章

Linux的权限控制

本章将和大家分享Linux中的权限控制。本章将和大家分享Linux中的权限控制。废话不多说,下面我们直接进入主题。 一、基础知识 Linux作为一种多用户的操作系统(服务器系统),允许多个用户同时登陆到系统上,并响应每个用户的请求。 任何需要使用操作系统的用户,都需要一个系统…

通过Jupyter Notebook+OpenAI+ollama简单的调用本地模型

通过Jupyter Notebook+OpenAI+ollama简单的调用本地模型 起因是收到了ollama的邮件,貌似支持使用openai来调用本地的ollama下载的模型为自己用想了下正好试下,因为这几天正好在尝试用Jupyter Notebook来写点调用api的方式来使用大语言模型,看看后面能不能自己做点有意思的操…

后门函数技术在二进制对抗中的应用

本次题目跟第七届HWS线下的re2有类似的地方,均有后门函数。二进制后门可以理解为:我们只需要修改某个字节或某个函数,就可以将加密的过程变成解密的过程,大大节省逆向成本。本题先对内置的dll进行解密,然后调用其加密函数对我们的txt进行加密,如果我们将加密的函数nop为解…

基于kalman滤波的UAV三维轨迹跟踪算法matlab仿真

1.程序功能描述使用卡尔曼滤波对UAV在三维空间场景中的运动轨迹进行预测和估计,最后输出预测轨迹,估计轨迹以及三维空间轨迹估计结果。2.测试软件版本以及运行结果展示 MATLAB2022a版本运行 3.核心程序for k=1:length(X_direct)-1%第一个估计 Xk_ = [X_direct(k);Vx_direct…

裴蜀定理学习记录

1477A - Nezzar and Board 观察到2x-y可以拆成x+(x-y),现在模拟一下这个过程发现得到的数可以看成从某个点xj出发,加上若干个两数之间的差的形式。 再考虑一下2x-y的几何意义,发现相当于在数轴上做x关于y的对称点,并且和数的分布位置有关,和具体数值是无关的 接下来有一个…

基于模糊PID的直流电机控制系统simulink建模与仿真

1.课题概述PID控制器和模糊PID控制器通过Simulink建模实现,在matlab中编程实现模糊控制规则,PID控制器参数计算。运行simulink模型之后,将2个控制器的控制响应曲线进行对比得到仿真结果。2.系统仿真结果 将PID控制器的控制响应曲线和模糊PID控制响应曲线放一起对比,结果如下…

公钥私钥gitee都不行,新手小白破局(windows凭据)

公钥私钥gitee都不行,新手小白破局(windows凭据) 创建时间:2024-07-26 一、问题复现 gitee项目创建后,由于之前的 账号密码错乱,导致提交不了,不能克隆下来,不能提交,如下: 1.1 初始的一个项目1.2 克隆出现问题二、删除公钥私钥 2.1 本机之前生成的密钥文件 一般在这…

【活动预告】Easysearch 结合大模型实现 RAG

2024 搜索客社区 Meetup 首期线上活动正式启动,本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,诚邀广大搜索技术开发者和爱好者参加交流学习。 活动时间:2024 年 7 月 31 日 19:30-20:30 (周三) 活动形式:微信视频号(极限实验室)直播 报名方式:关注或扫码海…

反射、特性

1.反射的例子:

SQL数据库表 多对多关系设计--省去链表的尝试

概述 之前遇到一个MES需求,需要创建一个基础资料表 "人员信息表" ,用于其它业务的人员信息关连,因为这些人员并非系统登录帐号,所以单独进行维护。人员表涉及到字段包括:ID,工号,姓名,所属工序,所属职称,所属车间。其中,所属工序、所属职称、所属车间 为…

Asp .Net Core 系列:详解授权以及实现角色、策略、自定义三种授权和自定义响应

什么是授权(Authorization)? 在 ASP.NET Core 中,授权(Authorization)是控制对应用资源的访问的过程。它决定了哪些用户或用户组可以访问特定的资源或执行特定的操作。授权通常与身份验证(Authentication)一起使用,身份验证是验证用户身份的过程,授权与身份验证相互独…

CTF-内存取证题目

一:使用volatility2版本 1、分析镜像 python2 vol.py -f /home/kali/桌面/worldskills3.vmem imageinfo 2、从内存中获取到用户admin的密码并且破解密码,以flag{admin,password}形式提交(密码为6位) (1)查看系统用户 python2 vol.py -f /home/kali/桌面/worldskills3.vme…