Golang基础-面向对象篇
文章目录
- struct结构体
- 类的表示与封装
- 类的继承
- 多态的基本要素与实现
- interface空接口
- 反射
- 变量的内置pair
- reflect包
- 解析Struct Tag
- Struct Tag在json中的应用
struct结构体
在Go语言中,可以使用type 关键字来创建自定义类型,这对于提高代码的可读性和可维护性非常有用。如type myint int,myint 是一个基于内置类型 int 创建的自定义类型。你可以在代码中使用 myint 类型,并对其进行操作,而它实际上是基础的 int 类型。
struct的定义如下:
package mainimport "fmt"// Book 定义一个结构体
type Book struct {title stringauth string
}func main() {var book1 Bookbook1.title = "Golang"book1.auth = "zhangsan"fmt.Println(book1)
}
// {Golang zhangsan}
需要注意的是 Go 语言中函数参数默认是值传递的。如果将book1对象传入函数中时,仅仅只是传进去一个副本,在函数中对book1的任何修改都是无效的。如果想在函数中修改原始变量,可以传递指向结构体的指针。如以下代码所示。
package mainimport "fmt"// Book 定义一个结构体
type Book struct {title stringauth string
}func changeBook(book *Book) {book.auth = "777"
}func main() {var book1 Bookbook1.title = "Golang"book1.auth = "zhangsan"changeBook(&book1)fmt.Println(book1)
}
// {Golang 777}
类的表示与封装
Go语言(通常称为Golang)不使用传统的类(class)和继承(inheritance)的概念,而是通过结构体(struct)来实现面向对象编程的特性。
go中没有public和private的关键字,如果类名大写,则其他包也能够访问;如果标识符以小写字母开头,则它是未导出的,只能在同一个包内访问。导出的标识符(大写字母开头)不仅仅限于结构体名字,还包括结构体中的字段名、函数名等。这种命名规范有助于代码的可维护性和封装性。
package mainimport "fmt"type Hero struct {Name stringAd intLevel int
}func (this Hero) Show() {fmt.Println("name =", this.Name)fmt.Println("Ad =", this.Ad)fmt.Println("Level =", this.Level)
}func (this Hero) GetName() string {return this.Name
}func (this Hero) SetName(newName string) {this.Name = newName
}func main() {hero := Hero{Name: "zhangsan", Ad: 100, Level: 1}hero.Show()hero.SetName("lisi")nowName := hero.GetName()fmt.Println("nowName =", nowName)
}
/*输出结果
name = zhangsan
Ad = 100
Level = 1
nowName = zhangsan
*/
可以看出,setName并没有把名字改为lisi。因为setName方法中使用的是值接收者(receiver),这意味着在该方法内部对Hero实例的修改不会影响到实际的hero变量。要使setName方法正确地修改Hero实例,需要将其改为指针接收者。如以下代码所示。
package mainimport "fmt"type Hero struct {Name stringAd intLevel int
}func (this *Hero) Show() {fmt.Println("name =", this.Name)fmt.Println("Ad =", this.Ad)fmt.Println("Level =", this.Level)
}func (this *Hero) GetName() string {return this.Name
}func (this *Hero) SetName(newName string) {this.Name = newName
}func main() {hero := Hero{Name: "zhangsan", Ad: 100, Level: 1}hero.Show()hero.SetName("lisi")nowName := hero.GetName()fmt.Println("nowName =", nowName)
}
/*输出结果
name = zhangsan
Ad = 100
Level = 1
nowName = lisi
*/
类的继承
现在有如下的一个Human类
package mainimport "fmt"type Human struct {name stringsex string
}func (this *Human) Eat() {fmt.Println("Human.Eat()...")
}func (this *Human) Walk() {fmt.Println("Human.Walk()...")
}func main() {h := Human{name: "zhangsan", sex: "male"}h.Eat()h.Walk()
}
现在有一个SuperMan类需要继承Human类,还有自己的level字段,并重写其中的Eat方法,还要能够写子类的新方法。代码如下:
type SuperMan struct {Human // SuperMan继承了Human类的方法level int
}// 重写父类的Eat()方法
func (this *SuperMan) Eat() {fmt.Println("SuperMan.Eat()...")
}// 添加子类新方法
func (this *SuperMan) Fly() {fmt.Println("SuperMan.Fly()...")
}
在继承完成后,main函数中定义子类的对象有两种方法。
第一种:一气通贯式
s := SuperMan{Human{"lisi", "female"}, 5}
第二种:守旧派
var s SuperMan
s.name = "lisi"
s.sex = "female"
s.level = 5
完整代码如下,都能成功运行。
package mainimport "fmt"type Human struct {name stringsex string
}func (this *Human) Eat() {fmt.Println("Human.Eat()...")
}func (this *Human) Walk() {fmt.Println("Human.Walk()...")
}// ===========================================type SuperMan struct {Human // SuperMan继承了Human类的方法level int
}// 重写父类的Eat()方法
func (this *SuperMan) Eat() {fmt.Println("SuperMan.Eat()...")
}// 添加子类新方法
func (this *SuperMan) Fly() {fmt.Println("SuperMan.Fly()...")
}func (this *SuperMan) Show() {fmt.Println("name =", this.name)fmt.Println("sex =", this.sex)fmt.Println("level =", this.level)
}func main() {h := Human{name: "zhangsan", sex: "male"}h.Eat()h.Walk()fmt.Println("=============")//方法一:定义子类新对象//s := SuperMan{Human{"lisi", "female"}, 5}//方法二var s SuperMans.name = "lisi"s.sex = "female"s.level = 5s.Walk() //父类方法s.Eat()s.Fly()s.Show()
}
/*运行结果
Human.Eat()...
Human.Walk()...
=============
Human.Walk()...
SuperMan.Eat()...
SuperMan.Fly()...
name = lisi
sex = female
level = 5
*/
多态的基本要素与实现
Go语言中用继承是无法实现多态的,需要用接口(interface)实现,它的本质是一个指针。
基本要素:
- 有一个父类(有接口)
- 有子类(实现了父类的全部接口方法)
- 父类类型的变量(指针)指向(引用)子类的具体数据变量
以下代码展示了一个使用接口的例子,定义了一个 AnimalIF 接口和两个实现该接口的类型 Cat 和 Dog。然后,通过 showAnimal 函数展示了如何使用接口进行多态性调用。
package mainimport "fmt"type AnimalIF interface {Sleep()GetColor() stringGetType() string
}type Cat struct {color string
}func (this *Cat) Sleep() {fmt.Println("cat is sleeping")
}func (this *Cat) GetColor() string {return this.color
}func (this *Cat) GetType() string {return "cat"
}//=================type Dog struct {color string
}func (this *Dog) Sleep() {fmt.Println("dog is sleeping")
}func (this *Dog) GetColor() string {return this.color
}func (this *Dog) GetType() string {return "Dog"
}func showAnimal(animal AnimalIF) {animal.Sleep()fmt.Println("color =", animal.GetColor())fmt.Println("kind =", animal.GetType())
}func main() {//var animal AnimalIF //接口的数据类型,父类指针//animal = &Cat{"Green"}//animal.Sleep()////animal = &Dog{"yellow"}//animal.Sleep()cat := Cat{"green"}dog := Dog{"yellow"}showAnimal(&cat)showAnimal(&dog)
}
在 main 函数中,我们创建了 Cat 和 Dog 的实例,并通过showAnimal 函数调用展示它们的信息。这里利用了接口的多态性,通过相同的接口来处理不同的类型。这种设计使得代码更加灵活,可以方便地扩展和添加新的类型。
interface空接口
在Go语言中,空接口(empty interface)是一种特殊的接口,它不包含任何方法签名。由于不包含任何方法,空接口可以表示任意类型。在Go中,空接口的声明形式是interface{}。
空接口的特点是它可以保存任意类型的值,因为任何类型都至少实现了零个方法,因此都满足空接口的要求。
package mainimport "fmt"func myFunc(arg interface{}) {fmt.Println("myFunc is called...")fmt.Println(arg)
}type Books struct {auth string
}func main() {book := Books{"zhangsan"}myFunc(book)myFunc(100)myFunc("haha")myFunc(3.14)
}
/*输出结果
myFunc is called...
{zhangsan}
myFunc is called...
100
myFunc is called...
haha
myFunc is called...
3.14
*/
在这个例子中,myFunc 函数接受一个空接口类型的参数,因此它可以接受任何类型的值。然后创建了一个 Books 结构体的实例 book,并将其作为参数传递给 myFunc 函数。
但是,interface{}如何区分此时引用的底层数据类型是什么?主要是通过断言机制来实现的。
func myFunc(arg interface{}) {fmt.Println("myFunc is called...")fmt.Println(arg)value, ok := arg.(string)if !ok {fmt.Println("arg is not string")} else {fmt.Println("value =", value)fmt.Println("arg is string")}
}
这种方式在运行时进行了类型检查,以确保转换的安全性。如果 arg 的实际类型不是 string,那么 ok 将为 false,并输出相应的提示信息。
反射
变量的内置pair
在Go中,如果定义了一个变量,那么它内部实际构造由两部分组成:变量类型type和值value。type可以划分成两类:static type和concrete type。
- static type指常见的数据类型,如int、string…
- concrete type指interface所指向的具体数据类型,是系统看得见的类型
变量类型type和值value组成了pair,反射主要是通过变量找到当前变量的具体类型或值。具体结构如下图所示。

package mainimport "fmt"func main() {var a string// pair<static_type:string,value:"aceld">a = "aceld"//pair<type:string,value:"aceld">var alltype interface{}alltype = astr, _ := alltype.(string)fmt.Println(str)
}
这段代码中,alltype.(string) 尝试将 alltype转为字符串类型,并返回两个值,一个是转换后的值 str,另一个是一个布尔值 ok 表示转换是否成功。在这里使用了 _ 来忽略不需要的第二个返回值。
如果转换成功,ok 为 true,则会打印出字符串的值。如果转换失败,ok 为 false,则会输出相应的提示信息。这种模式在处理接口类型时常用于确保类型安全。
reflect包
reflect主要包含了两个关键的接口,ValueOf实现输入任意数据类型返回数据的值,TypeOf实现输入任意数据类型,动态获取这个数据类型是static type还是concrete type。

可以用以下代码来判断:
package mainimport ("fmt""reflect"
)func reflectNum(arg interface{}) {fmt.Println("type:", reflect.TypeOf(arg))fmt.Println("value:", reflect.ValueOf(arg))
}func main() {var num float64 = 3.14159reflectNum(num)
}
/*输出结果
type: float64
value: 3.14159
*/
下面的代码演示了如何使用反射(reflection)获取结构体实例的字段和方法信息。
package mainimport ("fmt""reflect"
)type User struct {Id intName stringAge int
}func (this User) Call() {fmt.Println("User is called...")fmt.Printf("%v\n", this)
}func DoFiledAndMethod(input interface{}) {// 获取input的typeinputType := reflect.TypeOf(input)fmt.Println("inputType is:", inputType)// 获取input的valueinputValue := reflect.ValueOf(input)fmt.Println("inputValue is:", inputValue)// 通过type获取里面的字段// 1.获取interface的reflect.Type,通过Type得到NumField,进行遍历// 2.得到每个field,数据类型// 3.通过field有一个interface()方法得到对应valuefor i := 0; i < inputType.NumField(); i++ {field := inputType.Field(i)value := inputValue.Field(i).Interface()fmt.Printf("%s:%v=%v\n", field.Name, field.Type, value)}// 通过type获取里面的方法、调用for i := 0; i < inputType.NumMethod(); i++ {m := inputType.Method(i)fmt.Printf("%s:%v\n", m.Name, m.Type)}
}func main() {user := User{1, "Aceld", 18}DoFiledAndMethod(user)
}
/*输出结果
inputType is: main.User
inputValue is: {1 Aceld 18}
Id:int=1
Name:string=Aceld
Age:int=18
Call:func(main.User)
*/
解析Struct Tag
在 Go 语言中,可以为结构体的字段添加标签(tag),这些标签可以在运行时通过反射获取。标签通常用于提供额外的元数据,如字段的注释、验证规则等。
package mainimport ("fmt""reflect"
)type resume struct {Name string `info:"name" doc:"我的名字"`Sex string `info:"sex"`
}func findTag(str interface{}) {t := reflect.TypeOf(str).Elem() //当前结构体的全部元素for i := 0; i < t.NumField(); i++ {taginfo := t.Field(i).Tag.Get("info")tagdoc := t.Field(i).Tag.Get("doc")fmt.Println("info:", taginfo)fmt.Println("doc:", tagdoc)}
}func main() {var re resumefindTag(&re)
}
在以上代码中,resume 结构体的字段 Name 和 Sex 都有标签信息。在 findTag 函数中,通过 reflect.TypeOf(str) 获取结构体的类型,并使用 Elem() 方法获取实际的类型。然后,通过 t.Field(i).Tag.Get("info") 和 t.Field(i).Tag.Get("doc") 获取每个字段的 "info" 和 "doc" 标签的值。
Struct Tag在json中的应用
定义如下代码
package mainimport ("encoding/json""fmt"
)type Movie struct {Title string `json:"title"`Year int `json:"year"`Price int `json:"rmb"`Actors []string `json:"actors"`
}func main() {movie := Movie{"喜剧之王", 2000, 10, []string{"xingye", "zhangbozi"}}
}
对movie编码,即从结构体->json。从运行结果可以看出json中的键就是上面定义的Struct Tag
jsonStr, err := json.Marshal(movie)
if err != nil {fmt.Println("error:", err)return
}
fmt.Printf("jsonStr = %s\n", jsonStr)
//jsonStr = {"title":"喜剧之王","year":2000,"rmb":10,"actors":["xingye","zhangbozi"]}
对jsonStr解码,即从json->结构体
my_movie := Movie{}
err = json.Unmarshal(jsonStr, &my_movie)
if err != nil {fmt.Println("error:", err)return
}
fmt.Printf("%v\n", my_movie)
// {喜剧之王 2000 10 [xingye zhangbozi]}
相关文章:
Golang基础-面向对象篇
文章目录 struct结构体类的表示与封装类的继承多态的基本要素与实现interface空接口反射变量的内置pairreflect包解析Struct TagStruct Tag在json中的应用 struct结构体 在Go语言中,可以使用type 关键字来创建自定义类型,这对于提高代码的可读性和可维护…...
全国的科技创新情况数据分享,涵盖2020-2022年三年情况
随着国家对科技创新的重视和大力支持,全国的科技创新情况越来越受到关注。 我们根据中国城市统计年鉴的这方面指标,分析汇总得出全国科技创新情况数据,需要说明的是,由于统计年鉴指标调整,每一年的数据并非字段相同&a…...
visionOS空间计算实战开发教程Day 1:环境安装和编写第一个程序
安装 截至目前visionOS还未在Xcode稳定版中开放,所以需要下载Xcode Beta版。比如我们可以下载Xcode 15.1 beta 2,注意Xcode 15要求系统的版本是macOS Ventura 13.5或更新,也就是说2017年的MacBook Pro基本可以勉强一战,基…...
java常见数值类型取值范围/ int short long BigInteger取值范围
文章目录 一、各类型取值范围 一、各类型取值范围 以下整理java中常用的数值类型取值范围。 类型字节大小最小值最大值取值范围byte8bit-128127-128到127short16bit-2 15 ^{15} 152 15 ^{15} 15-1-32768-32767int32bit-2 31 ^{31} 312 31 ^{31} 31 -1-2,147,483,648 到 2,147…...
echarts产品日常奇怪需求
设置最小刻度导致好多小数,限制两位 yAxis 指定的y轴设置 axisLabel,可以格式化显示 文档地址:https://echarts.apache.org/zh/option.html#yAxis.axisLabel.formatter yAxis: [{type: value,name: 利率,position: right,alignTicks: true,mi…...
CSDN文章保存为MD文档(一)
免责声明 文章仅做经验分享用途,利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任,一旦造成后果请自行承担!!! import os import re i…...
【tomcat】java.lang.Exception: Socket bind failed: [730048
项目中一些旧工程运行情况处理 问题 1、启动端口占用 2、打印编码乱码 ʮһ�� 13, 2023 9:33:26 ���� org.apache.coyote.AbstractProtocol init ����: Fa…...
什么是高防IP?有什么优势?怎么选择高防IP?
在当今的互联网环境中,分布式拒绝服务(DDoS)攻击已经成为一种常见的安全威胁。这种攻击通过向目标服务器发送大量的无效流量,使其无法处理正常的请求,从而达到迫使服务中断的目的。作为一个用户,你是否曾遇…...
不存在类型变量 A, T 的实例,使 Collector<T, A, List<T>> 符合 Supplier<R>
报错信息 原因: 不存在类型变量 A, T 的实例,使 Collector<T, A, List<\T>> 符合 Supplier<\R> 来源 测试Stream流的map方法,做算法习惯基本类型定义数组。 map方法:Stream API的一部分。允许以一种声明式的方式处理数据,…...
千兆光模块和万兆光模块的供应链管理
随着网络通信技术的不断发展,千兆光模块和万兆光模块已逐渐成为现代网络建设中不可缺少的组成部分。它们在云计算、数据中心、大规模机房以及企业内部网络等领域广泛应用,已经成为大家熟知的产品。 千兆光模块和万兆光模块的工作原理基本相同ÿ…...
pytorch训练出现的bug
训练过后发现.csv文件左侧出现了几列unname和一列0,1,2。这个时候在训练就会从unname那一列开始训练。我们需要把这几列删除,之后再重新训练 问题应该是执行完了这个语句过后就会出现了。 执行完后,记得删。...
【AGC】集成AGC服务上架应用市场审核问题
【关键字】 AGC、应用市场、审核 【问题描述】 集成了AGC服务,上架到应用市场不通过,检查发现是com.huawei.secure.android.common.ssl.util.c.doInBackground 存在获取安装列表行为。 已经按照sdk 设置了,但是检测还是有授权前去获取安装列…...
element emitter broadcast向下广播 dispatch向上分派
emitter 项目使用element的emitter.js,做个使用记录 function broadcast(componentName, eventName, params) {this.$children.forEach(child > {const name child.$options.name;if (name componentName) {child.$emit.apply(child, [eventName].concat(para…...
基于 Modbus 的工业数据采集、控制(part 2)
基本处理流程 服务器 parse_and_process(char * input)//input :post请求发送的正文 {...// 请求 modbus 数据else if(strstr(input, "modbus_get")){return handle_get(sock, input);}// 控制 modbus 设备else if(strstr(input, "modbus_set")){return …...
vue前端项目如何配置后端项目的请求地址
在 Vue 前端项目中配置后端项目的访问地址可以通过修改项目的配置文件来实现。Vue 常用的配置文件是 vue.config.js,你可以按照以下步骤进行配置: 在 Vue 项目的根目录下,创建或编辑 vue.config.js 文件。 在 vue.config.js 中,可…...
Lora学习资料汇总
目录 LoRa联盟 Semtech lora网关供应商: LoRaMAC API文档 论坛 开发板 主流技术对比分析 LoRa网络距离模拟测试方法 LoRa应用 LoRa联盟 LoRa联盟:LoRaWAN规范的制定组织 https://www.lora-alliance.org/ LoRa技术白皮书:https://www.lora-alli…...
Oracle的控制文件多路复用,控制文件备份,控制文件手工恢复
一.配置控制文件多路复用 1.查询Oracle的控制文件所在位置 SQL> select name from v$controlfile;NAME -------------------------------------------------------------------------------- /u01/app/oracle/oradata/orcl/control01.ctl /u01/app/oracle/fast_recovery_a…...
在线视频课程教育系统源码/网课网校/知识付费/在线教育系统/在线课程培训系统源码
源码简介: 在线视频课程教育系统源码,作为网课/网校/知识付费/在线教育系统,它有文章付费阅读在线点播自动发货付费阅读VIP会员系统等功能。它是实用的在线课程培训系统源码。 发货100-在线视频课程教育系统,它是一款功能实用的…...
程序员护城河:保障系统安全与网络稳定的不可或缺力量
引言: 在当今数字化时代,计算机和互联网的广泛应用使得程序员的角色变得越来越重要。作为保障系统安全与网络稳定的关键力量,程序员需要具备一系列的基本能力,同时还需掌握一些专业技术和策略,以确保系统运行的安全性…...
html属性值可以不用引号吗,实例验证
html属性值可以不用引号 HTML元素的属性值可以不适用引号来包裹,浏览器一样可以将其进行渲染。不过,如果这样写HTML的代码的话,属性与属性值之间需要用空格来进行隔开,避免后面的属性变成前面属性的属性值。 提示:虽…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
