Golang 学习(一)基础知识

news2024/12/26 22:26:52
面向对象
  • Golang 也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。

  • Golang 没有类(class),Go 语言的结构体(struct)和其它编程语言的类(class)有同等的地位,Golang 是基于 struct 来实现 OOP 特性的,去掉了传统 OOP 语言的继承、方法重载、构造函数和析构函数、隐藏的 this 指针等等

  • Golang 仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它 OOP 语言不一样,比如继承 :Golang 没有 extends 关键字,继承是通过匿名字段来实现。

  • Golang 面向对象(OOP)很优雅,OOP 本身就是语言类型系统(type system)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。

一、基础知识

数据类型

在这里插入图片描述

在这里插入图片描述

## golang字符类型
字符类型的本质是一个整数,占8个字节(Go 的字符串是由字节组成的,根据utf-8编码)
字符型 存储到 计算机中,需要将字符对应的码值(整数)找出来
存储:字符—>对应码值---->二进制–>存储
读取:二进制----> 码值 ----> 字符 --> 读取
字符和码值的对应关系是通过字符编码表决定的(是规定好)
## golang字符串类型
两种表现形式:
(1) 双引号, 会识别转义字符
(2) 反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果

溢出问题

	a := int8(127)
	b := int8(1)
	fmt.Println(a + b) // 输出-128,不会报错
	
	a := uint8(255)
	b := uint8(1)
	fmt.Println(a + b) //输出0,不会报错

rune 类型:相当int32,由于golang中的字符串底层实现是通过byte数组的,中文字符在unicode下占2个字节,在utf-8编码下占3个字节

  • byte 等同于int8,常用来处理ascii字符
  • rune 等同于int32,常用来处理unicode或utf-8字符
数组和切片

数组:

  • 数组的地址可以通过数组名来获取 &intArr
  • 数组的第一个元素的地址,就是数组的首地址
  • 数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 -> 8 int32->4…

切片:

slice 底层数据结构是由一个 array 指针指向底层数组,len 表示切片长度,cap 表示切片容量

当扩容时:

  • 假如 slice 容量够用,则追加新元素进去,slice.len++,返回原来的 slice。
  • 当原容量不够,则 slice 先扩容,扩容之后 slice 得到新的 slice,将元素追加进新的 slice,slice.len++,返回新的 slice。
扩容规则:
	当切片比较小时(容量小于 1024),则采用较大的扩容倍速进行扩容(新的扩容会是原来的 2 倍),避免频繁扩容,从而减少内存分配的次数和数据拷贝的代价。当切片较大的时(原来的 slice 的容量大于或者等于 1024),采用较小的扩容倍速(新的扩容将扩大大于或者等于原来 1.25 倍),主要避免空间浪费

和切片的区别:

  • 1)数组是定长,访问和复制不能超过数组定义的长度,否则就会下标越界,切片长度和容量可以自动扩容
  • 2)数组是值类型,切片是引用类型,每个切片都引用了一个底层数组,切片本身不能存储任何数据,都是这底层数组存储数据,所以修改切片的时候修改的是底层数组中的数据。切片一旦扩容,指向一个新的底层数组,内存地址也就随之改变
Channel

go中的channel是一个队列,遵循先进先出的原则,负责协程之间的通信,channel 是 goroutine 之间数据通信桥梁,而且是线程安全的,写入,读出数据都会加锁。

三种类型:只读 channel、只写 channel(意义在于在参数传递时候指明管道可读还是可写,即使当前管道是可读写的)、可读可写 channel

channel 中只能存放指定的数据类型
channle 的数据放满后,就不能再放入了
在没有使用协程的情况下,如果 channel 数据取完了,再取,就会报 dead lock
goroutine 中使用 recover,解决协程中出现 panic,导致程序崩溃问题

应用场景:

  • 停止信号监听
  • 定时任务
  • 生产方和消费方解耦
  • 控制并发数

底层原理:

img

有缓冲的channel使用ring buffer(环形缓冲区)来缓存写入的数据,本质是循环数组(为啥用循环数组?普通数组容量固定、更适合指定的空间,且弹出元素时,元素需要全部前移)

流程:

## 写数据
如果channel的读等队列存在接受者goroutine
将数据直接发送给第一个等待的goroutine,唤醒接收的goroutine
如果channel的读等队列不存在接受者goroutine
    如果循环数组的buf未满,那么将数据发送到循环数组的队尾
    如果循环数组的buf已满,将当前的goroutine加入写等待对列,并挂起等待唤醒接收
## 读数据
如果channel的写等待队列存在发送者goroutine
    如果是无缓冲channel,直接从第一个发送者goroutine那里把数据拷贝给接收变量,唤醒发送的gorontine
    如果是有缓冲channel(已满),将循环数组buf的队首元素拷贝给接受变量,将第一个发送者goroutine的数据拷贝到循环数组队尾,唤醒发送端goroutine

如果channel的写等待队列不存在发送者goroutine
    如果循环数组buf非空,将循环数据buf的队首元素拷贝给接受变量
    如果循环数组buf为空,这个时候就会走阻塞接收的流程,将当前goroutine加入读等队列,并挂起等待唤醒
## 相比较共享内存
    共享内存访问需要加锁,若持锁失败,要么忙等重试,要么待会儿再来。
    降低耦合:channel以消息传递通信,消息发出后就不用管了,除非它希望得到回馈,完全异步。

Map

原理:底层使用 hash table,每个 map 的底层结构是 hmap,是有若干个结构为 bmap(链表) 的 bucket 组成的数组。用链表来解决冲突 ,出现冲突时,不是每一个 key 都申请一个结构通过链表串起来,而是以 bmap 为最小粒度挂载,一个 bmap 可以放 8 个 kv。在哈希函数的选择上,会在程序启动时,检测 cpu 是否支持 aes,如果支持,则使用 aes hash,否则使用 memhash。

key 可以是很多种类型,比如 bool, 数字,string, 指针, channel ,,接口, 结构体, 数组,slice, map 还有 function 不可以,因为这几个没法用 == 来判断

声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用

map对象不是线程安全的,并发读写的时候运行时会有检查,遇到并发问题就会导致panic

## 内存回收
1. go 底层map 是由若干个bmap(桶)构成的,桶只会扩容,不会缩容 ,所以 map中占用的内存不会被释放
以上只针对值类型的数据结构 例如:基本类型 int string slice struct 等
2. 如果key为 指针变量 删除后这个指针变量内存不会释放,但是这个指针指向的对象,引用计数会 -1 如果引用计数为0 在gc的时候就会被释放!

## 元素有序性
map 因扩张⽽重新哈希时,各键值项存储位置都可能会发生改变,顺序自然也没法保证了,所以官方避免大家依赖顺序,直接打乱处理,每次遍历,得到的输出 可能不一样。
for range map 在开始处理循环逻辑的时候,就做了随机播种(要想有序遍历,可以先将 key 进行排序,然后根据 key 值遍历)

## 线程安全
map对象不是线程安全的,并发读写的时候运行时会有检查,遇到并发问题就会导致panic
解决方法:使用sync.Map、使用读写锁
结构体
type Person struct {
	Name string `json:name-field`
	Age int
}
  • 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名 ,但 go 做了一个简化,也支持 结构体指针.字段名, 更加符合程序员使用的习惯,go 编译器底层 对 person.Name 做了转化 (*person).Name。
  • 结构体的所有字段在内存中是连续的
  • 结构体进行 type 重新定义(相当于取别名),Golang 认为是新的数据类型,但是相互间可以强转(和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)
  • struct 的每个字段上,可以写上一个 tag, 该 tag 可以通过反射机制获取,常见的使用场景就是序
    列化和反序列化。
函数与方法
//函数
func getArea(R int) float64 {
	return math.Pi * math.Pow(R, 2)
}
//方法
func (c Circle)getArea() float64 {
	return math.Pi * math.Pow(c.R, 2)
}

方法的调用和传参机制和函数基本一样,不一样的地方是方法调用时,会将调用方法的变量,当做实参也传递给方法,体现了封装性。函数则是无状态的代码块。

Go 的函数参数传递都是值传递:调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

对象
make和new

1)作用变量类型不同,new给string,int和数组分配内存,make给切片,map,channel分配内存;2)返回类型不一样,new返回指向变量的指针,make返回变量本身;3)new 分配的空间被清零。make 分配空间后,会进行初始化;

在这里插入图片描述

继承
type Person struct {
	id int
	name string
	age  int
}

type Student struct {
	Person
	id int
	score     int
	className string
}
  1. 使用匿名属性,来实现继承:即将父类作为子类的匿名属性
  2. 如果父类和子类中有重复字段,则优先使用子类自身的属性
  3. 方法的重写(方法名,参数,返回值类型都必须一样)此时调用方法绑定的对象不在时父类而是子类本身
接口
  1. 空接口
// fmt包中的方法 Println底层
func Println(a ...interface{}) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}
// 接纳任意对象
var i interface{} = 45
i=[...]int{1,2,3}

可以接纳任意对象,类似java中的Object

  1. 接口

可以定义一些通用的方法,将被继承和实现的接口以匿名属性传入即可,但不必将所有的方法都实现

type annimal interface {
	eat()
	sleep()
	run()
}
type cat interface {
	annimal
	Climb()
}
  1. 多态

可以在调用方法时会因传入对象的不同而得到不同的效果

// 使用 对象.(指定的类型) 判断改对象是否时指定的类型
if data,ok :=v.(cat);ok{
			data.eat()
			fmt.Println("this is HelloKitty : ")
		}

实现接口中的方法可以通过指针和结构体绑定

type animal interface {
	eat()
}
type Dog struct {
	Name string
	Age  int
}
//func (d Dog) eat() { 结构体绑定
//}
func (d *Dog) eat() { 指针绑定
}

func main() {
	var a animal
	dPoint := &Dog{
		Name: "susan",
		Age:  12,
	}
	dStruct := Dog{
		Name: "susan",
		Age:  12,
	}
	a = dPoint
	// 使用指针接收者实现接口不能存结构体类型变量
	// a = dStruct
}

区别:使用值接受者实现接口,结构体类型和结构体指针类型的变量都能存,指针接收者实现接口只能存指针类型的变量

异常
  1. 编译时异常:在编译时抛出的异常,编译不通过,语法使用错误,符号填写错误等等。。。
  2. 运行时异常:在程序运行时抛出的异常,这个才是我们将要说的,程序运行时,有很多状况发生,例如:让用户输入一个数字,可用户偏偏输入一个字符串,导致的异常,数组的下标越界,空指针等等。。。。

编译时异常很容易找到,而运行时异常不容易提前发现,通过if err != nil判断,但是依然会漏掉很多异常,因此我们需要在运行过程中动态的捕获异常

defer和recover

defer:延时执行,即在方法执行结束(出现异常而结束或正常结束)时执行
recover:恢复的意思,如果是异常结束程序不会中断,返回异常信息,可以根据异常来做出相应的处理
recover必须放在defer的函数中才能生效

func test(a int, b int) int {
	defer func() {
		err := recover()
		fmt.Println("err:",err)
	}()
	a = b / a
	return a
}
func main() {
	i := test(0, 1)
	fmt.Println("====main方法正常结束!!====",i)
}

//结果:
err: runtime error: integer divide by zero
====main方法正常结束!!==== 0
手动抛出异常——panic

有些异常是不应该恢复的,应该抛出异常,可以让这个异常一层层的返回给调用方的程序,使其不能继续执行,从而起到保护后面业务的目的

func test(a int) int {
	i:=100 - a
	if i<0{
		panic(errors.New("账户金额不足!!!!"))
	}
	fmt.Println("=======账户扣款=====")
	return i
}

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

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

相关文章

源码梳理(3)MybatisPlus启动流程

文章目录 1&#xff0c;MybatisPlus的使用示例2&#xff0c;BaseMapper方法的执行2,1 MybatisMapperProxy代理对象2.2 InvocationHandler接口&#xff08;JDK动态代理&#xff09;2.3 MapperMethodInvoker接口2.4 MybatisMapperMethod 3&#xff0c;SqlSession的执行流程3.1 Sq…

AUTOSAR内存篇 -EEPROM Abstraction(EA)

文章目录 功能介绍一般行为寻址机制和分段地址计算擦/写次数限制“立即” 数据的处理管理块一致性信息总结本文介绍关于EEPROM Abstraction相关的内容。下图所示为内存硬件抽象层的模块架构图。 EEPROM抽象(EA)从器件特定的寻址方案和分段中抽象出来,并为上层提供虚拟寻址方…

100000行级别数据的 Excel 导入优化之路

项目中有一个 Excel 导入的需求&#xff1a;缴费记录导入 由实施 / 用户 将别的系统的数据填入我们系统中的 Excel 模板&#xff0c;应用将文件内容读取、校对、转换之后产生欠费数据、票据、票据详情并存储到数据库中。 在接手之前可能由于之前导入的数据量并不多没有对效率…

冀蒙辽三地共同推进北斗卫星导航定位基准站资源共享

冀蒙辽三地共同推进北斗卫星导航定位基准站资源共享 近期&#xff0c;冀蒙辽三地共同举办了“北斗卫星导航定位基准站资源共享推进会”&#xff0c;旨在推动北斗卫星导航定位系统的规模化应用&#xff0c;加强区域北斗卫星导航定位基准站网络的协同服务能力&#xff0c;为经济…

QT 槽函数的五种写法

前三种写法&#xff1a; 方法五&#xff1a;

clr的执行模型-笔记

学习来源&#xff1a;《CLR via C by Jeffrey Richter 》第四版&#xff0c;第1章 clr的执行模型 1.C#编译生成执行程序集文件 编译文件的组成&#xff1a;pe32/pe32头&#xff0c;clr头&#xff0c;元数据&#xff0c;IL pe32/pe32头&#xff1a;windows标准执行文件头 cl…

FPGA平台以太网学习:涉及1G/2.5G Ethernet 和Tri Mode Ethernet MAC两个IP核的学习记录(二)——IP学习使用

文章目录 一、传输速率二、网口标准选择三、核功能选择四、共享逻辑五、总结&#xff08;重点&#xff09; 学习不能稀里糊涂&#xff0c;要学会多思考&#xff0c;发散式学习以及总结&#xff1a; FPGA作为一种器件&#xff0c;只是实现目的的一种方法&#xff0c;过度追求实现…

第二十四回 王婆计啜西门庆 淫妇药鸩武大郎-Numpy索引和切片操作示例

郓哥被王婆打了&#xff0c;就去找武大郎。将情况一说&#xff0c;两人商定去抓奸。一天武大郎只做了两三扇炊饼&#xff0c;约好了时间&#xff0c;郓哥进去顶住大门不让王婆关&#xff0c;武大郎直接跑进去&#xff0c;西门庆刚开始躲到床底下&#xff0c;后被潘金莲提醒&…

Uibot (RPA设计软件)智能识别信息+微信群发助手(升级版)———课后练习1

微信群发助手机器人的小项目友友们可以参考小北的课前材料二博客~ (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff09; 紧接着小北的前两篇博客&#xff0c;友友们我们即将开展新课的学习~RPA 培训前期准备指南——安装Uibot(RPA设计软件&#x…

微信小程序(三十五)双向绑定警告去除方法

该警告的出现原因是开发者工具自身的不足&#xff0c;但在调试过程中容易刷屏&#xff0c;这里讲一下解决方法 1. 在双向绑定后面绑定一个空函数&#xff08;bind:input"emptyfn"&#xff09; <input type"text" model:value"{{keyword}}" b…

物业公司数字档案室建设要求

物业公司数字档案室建设的要求可以包括以下几个方面&#xff1a; 1. 硬件设备&#xff1a;需要配置足够的计算机、服务器、网络设备等硬件设备&#xff0c;以支持档案的数字化存储和管理。 2. 软件系统&#xff1a;需要选择专久智能档案管理软件系统&#xff0c;确保可以方便地…

基于微信小程序的校园水电费管理小程序的研究与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

不关电脑因为懒?你们不懂程序员!

笔者作为一只老程序猿&#xff0c;确实没有关电脑的习惯。有人说不关电脑因为懒&#xff0c;那只能说这个想法too young~ 这个问题的答案可能因人而异&#xff0c;但一般来说&#xff0c;程序员不喜欢关电脑的原因可能包括以下几个方面&#xff1a; 工作需要&#xff1a;对于…

用握力器玩谷歌小恐龙游戏(三)

往期回顾 用握力器玩谷歌小恐龙游戏&#xff08;一&#xff09; 用握力器玩谷歌小恐龙游戏&#xff08;二&#xff09; GS-GAME-PC 前言 这次更新主要是&#xff0c;将原来的使用Wifi Mesh串口接收上位机的方法&#xff0c;改成了蓝牙直连电脑的方式&#xff0c;这种方式的…

Google Chrome Close AutoUpdate

DOMException: play() failed because the user didn‘t interact with the document first.-CSDN博客 html5 audio video-CSDN博客 Google Chrome Close AutoUpdate 关闭google浏览器自动更新 1&#xff1a;检查是否已安装google浏览器&#xff0c;并卸载&#xff1a; 2&…

【JS】基于node-media-server搭建流媒体服务器示例

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍基于node-media-server搭建流媒体服务器示例。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

【Shell的运行原理以及Linux当中的权限问题】

Shell的运行原理以及Linux当中的权限问题 Shell的运行原理Linux当中的权限问题Linux权限的概念如何实现用户账号之间的切换如何仅提升当前指令的权限如何将普通用户添加到信任列表 Linux权限管理文件访问者的分类 (人)文件类型和访问权限 (事物属性)文件权限值的表示方法文件访…

少儿编程考级:智慧启迪还是智商税?

在当前科技日新月异的时代背景下&#xff0c;少儿编程教育日益受到家长和社会的广泛关注。与此同时&#xff0c;各类少儿编程考级应运而生&#xff0c;引发了公众对于其价值和意义的深度探讨。一部分人认为这是对孩子逻辑思维与创新能力的有效锻炼&#xff0c;是智慧启迪的重要…

业务拓展利器!跨境电商如何选对代理IP?IPIDEA 一键连接全球商机!

文章目录 一、跨境电商发展与海外代理IP的重要性1.1 跨境电商的发展现状1.2 海外代理IP在跨境电商中的重要性 二、选对代理IP品牌的关键因素三、IPIDEA海外IP代理的优势3.1 IPIDEA的优势3.2 IPIDEA提供的代理类型 四、使用IPIDEA爬虫实战五、总结 一、跨境电商发展与海外代理IP…

算法——二分查找算法

1. 二分算法是什么&#xff1f; 简单来说&#xff0c;"二分"指的是将查找的区间一分为二&#xff0c;通过比较目标值与中间元素的大小关系&#xff0c;确定目标值可能在哪一半区间内&#xff0c;从而缩小查找范围。这个过程不断重复&#xff0c;每次都将当前区间二分…