Go语言并发微服务分布式高可用
Go语言基础
环境安装
命令行输入go,当前操作系统Os环境中依赖于PATH指定的日录们去找命令(可执行文件)windows会优先搜索当前日录,当前日录没有才依赖PATH中指定的日录
环境变量: 操作系统运行环境中提前定义好的变量PATH: 如果你在命令行中输入了一段字符,shell要解析它,被解释为可执行的文件(命令)命令:某些程序员写好的可执行文件
GO运行环境
GOROOT: GO的安装路径 c:/go/1.20.4
GOPATH:
当前用户家目录/qo ~/go SHOME/go,
目前第三方包安装目录
第三方包如果instal1就要编译可执行文件,就放在bin日录中
pkg目录: 缓存 第三方包文件
bin目录: 第三方包通过go install命令下载并编译好的可执行文件的存放处
dlv 调试qo代码
gopls go的自动完成、编辑支持等
go instal1 命令:下载第三方包到SGOPATH/go/下面的缓存包文件们到该目录,编译好可执行文件放到SGOPATH/go/biigo get命令:下载第三方包到SGOPATH/go/下面的缓存包文件们到该目录,以后编程用这些包如何知道该qo install还是 go get,官方文档会告诉你PATH:增加了~/go/bin目录 等价于 GOPATH + bin
必须,go在这里必须,bin” />
UserName大驼峰,首字母大写大驼峰
userName小驼峰
user name snake 它形命
100 a指代100,a就是指代100的一个名称,标识符a=100 是数字,常量,不可变的值,宁面常量100 + 1 = 101,100还是那个100,1还是那个1, 101就是101
100 +2
100 +3
0
8X2
384
a = 200 说明 a的指代可以变化,a变心了,可以变化指代值的标识符,称为 恋量标识符如果说a的指代一旦关联,不可变,a这个标识符指代的值不能改变了,称为 常量标识符
1.25
true
false iota
nil
“ab”0= “abc”
变量名var
总结: iota是在成批定义和序列有关的常量定义
其他语言中const a = [1, 2]a = [1] // 不可以
go语言中,常量不可以用数组
“abc”赋值语句,名称是a,被赋值,a是一个指代,指向某个值
=
1
100
如果可以,再次可以赋值,a称为变量,a的指代可以发生变化
如果不以
a有类型要求,不可以改变类型,同类型可以再次赋值,a是变景 (a=100不可以,a=”aaa”可以)a就是不可以再被赋值,a和第一个赋给它的值之间的联系不可改变,a称为常量标识符
标识符的指向的值一旦建立,不可改变,要求定义是必须建立关联常量:变量:标识符的指向的值建立后,可以改变1类型也可以变,往往动态语言JS、Python,举例 a = 100,a=”abc”,a=[1,2,3]2同类型可以变
const a =”abc”赋值语句,右边是无类型常量,它的缺省类型是string,左边a没有指定类型,a会进行类型推导,会依赖右边的类型,所以,a被推测为string类型类型推导可以用在常量、变量定义,包括批量定义时
var a int,b strinq // 不支持,批量定义 var ()var a int,b int // 不可以var a,b int // 可以,如果要写在一行,必须同类型,只需要在最后指定类型就行。该例子用零值var c,d int = 100,200 // 如果要写在一行,必须同类型,只需要在最后指定类型就行。可以赋值,但要全部对应给出值
变量的短格式b // 不是短格式,什么都不是,不是赋值语句,也没有const、vara := 100 // 赋值语句,短格式变量定义语句,定义变量。定义了变量标识符a,右边可以用来推导a的类刑为int
var a int //零值0// a := 200 // 重复定义ab := 123,”abcd”// 党然可以” />
标识符写源代码时候,用来指代某个值的。编译后还有变量、常量标识符吗?没有了,因为数据在内存中,内存访间靠什么? 地址,标识符编详后就没有了就换成了地址了
源代们本质是文本文件编详 ,源代码编程成一进制可执行文件运行这个赚盘上的二进制可执行文件,运行在当前8上,变成进程,进程要不要占内存空问,要的吗?李量、常量、值在这块内存中放者
bool在go中不是int类型,也不是其他整数类型。在go中,bool就是布尔型,和整型没有关系,就是完全不同的类型GO是对类型近乎苛刻的语言
int、uint、int64、uint64,这四个都是完全不同的类型,不能瓦操作
计算机世界这有二进制数据,每一个位bit表示0或者1,最多表达2种可能性
有符号、无符号类型
u unsigned 无符号,以int8、uint88bits,总共能够表达256种状态int8,1 byte,8 bits,表示正负数将最高位留出来不能表示数据状态,用0表示负,用1表示正,剩余7位表示数宁能够表示多少个不同的数字呢” />
强制类型转换:显式 指明 类型转换,有可能失败fmt .Println(a + int (m)) // int (m)
string(整数值看做是ascii或unicode码) 去查编码表
var c rune = 300 // type rune = int32 类型 别名,type定义时使用了 =你等于我,你就是我
type myint int32 // 特别注意这里没有等号=,这不是别名
fmt.Println Print line 输出到控制台换行
fmt.Printf(“%[2]T 号[IJdn”,rune(m),string(m)) 值从1开始编 index1? 下一个如果没有指定索引,索引默认是indext1
fmt.Printf(“%T T %T 8T n”, a, b,c, a t b + c) // format
Printf 往控制台打印,f是format
% 占位符,和后面的值依次对应
%T 表示type,取值的类型
%d digital 数值形式,往往用于整数
b用string类型的值带字符串类型引号的s,quote引号A
0o101 => 0b 001 000 001 => 0b0100 0001 => 0x41 => 65单引号留给了表示字符,字面量表达,本质上是int32 (rune) 或byte (uint8)双引号和反引号用来表示字符串字面量。反引号
其中使用双引号、单引号多行
主要用途: 结构体tag使用
字符串或字符中,占用的字节数(因为我们要关心内存占用和磁盘占用),显示中在不同的显示设备中展示的显示宽度tab对应的显示宽度可以调整12345678
y
和
Xyz
XXXxXx
XXXXXXXX
“x\ty\n\riz’ nnx\ty\n\”izI\n
*int 指向int类型数据的指针0xc000018088 表示门牌号码门里面房间里面住着数据
赋值在Go中,往往是建立副本
if 后必须是boolswitch 后面是什么类型” />
顺序sequence不是排序sort
o
容器元素个数 + 1
append如同排队,在队尾后增加即可insert插队队最尾巴后插队,就是append中间插队,占用当前位置,把当前位置与其后所有数据后移队首插队,所有元素统统后移挪动数据是要耗时间的,挪动的元素越多(规模越大),代价越大
容器元素个数 – 1
pop队尾元素移除,影响最小
remove如果是队尾,就是pop
中间离队,后面数据统统前移队首离队,后面数据统统前移
挪动数据是要耗时间的
w
元素个数len 不变定位问题
更新内容
8
定位问题:
使用索引,首地址 + 该类型的宁节数 偏移,所以,定位要用索引计算得到元素的内存地址,不用遍历,效率极高。顺序表不管有多少个元素,都是一个四则元泰公式直接推出来如果使用内容定位,内容比较,遍历的方式挨个比较内容,效率低下。最不幸,遍历完了,才知道没有
获取内容:使用索引直接定位该位置,拿走内容遍历:容器中的元素,不管有没有顺序,我们都要不重复的将所有元素挨个揽一遍。首地址开始始,挨个偏移取内容前提: 要数据规模,如果数据规模小,随便你玩。数据规模人,都是事顺序表适合仅仅在尾部增删扩客问题
链接表:每一个元素存储在内存中,但是元泰并不是连续的存储在内存中,做落内存的不同位置,前一个元素指向下一个元素(链接)
简称链表
可变
元素可变容器可变。Go中数组是容器不可变的
CRUD 遍历,Create增,Read 读取,Update 改,Delete删
二分法查找有一个前提,就是已经为元素排过顺序了,而排序非常非常耗时,非必要不要做排序sort容器的元素个数不能变了。数组必须给出长度,以后数组这个容器不能增删元素了,不能扩容了。长度是死的,必须定义时给出容器不可变,[…Jintf)[常量]int早面有元素,元素的内容可变顺序表实现
数组
可以索引
值类型” />
长度可变,元素个数可变
底层必须使用数组引用类型,和值类型有区别
切片一定要关注len和cap
内存模型
组合结构
1 底层数组,数组容量不可变,元素内容能变2 slice header标头值或slice descriptor描述符
type slice struct f
array unsafe.Pointer // 指针,指向底层数组的首地址int // 表示当前切片的元素个数lenint // 表示当前切片可以最多放几个元素
cap
注意上面三个结构体的属性都是小写,所以包外不可见。len函数取就是len属性,cap函数取cap属性。指针可以通过取底层数组的第一个元素的地址,即切片第一个元素的地址
组合结构
1 底层数组,数组容量不可变,元素内容能变2 slice header标头值或slice descriptor描述符
type slice struct {array unsafe.Pointer // 指针,指向底层数组的首地址int // 表示当前切片的元素个数lenint // 表示当前切片可以最多放几个元素
cap
注意上面三个结构体的属性都是小写,所以包外不可见。len函数取就是len属性,cap函数取cap属性。指针可以通过取底层数组的第一个元素的地址,即切片第一个元素的地址
var al = make([lint,1,5)切片长度len为1,容量cap为5,本质上数据的存储利用底层数组,素是存储在底层数组中,打印[0)var a0 = []int[10, 1l, 12]
[]int 切片类型
元素有3个,len为3;容量cap为3打F[10 11 121&a0表示切片的地址,header这个结构体的地址&a0[0] 第一个元素的地址,由于第一个元素存在底层数组中,数组的第一个元素地址就是数组的地址
append(切片,1) append(切片,1,11,111)
指针可 以通过取底层数组的第-个元素的地址,即切片第一一个元素的地址
var al = make([lint,1,5)切片长度len为1,容量cap为5,本质上数的存储利用底层数组,元素是存储在底层数组中,打印101var a0 = []int{10,11, 12][]int 切片类型
元素有3个,len为3;容量cap为3打Dr10 11 121&a0表示切片的地址,header这个结构体的地址6a0101 第一个元素的地址,由于第一个元素存在底层数组中,数组的第一个元素地址就是数组的地加
append(切片,1)append(切片,1,11,111)
切片
选取当前切片的一段等到一个新的切片,共用底层数据(因为不扩容),但是header中的三个属性会变slice[start:end] 前包后不何cap的意思是,从header中指针开始向后到底层数组的最后一个元素的位置还能容纳几个元素len = end – start,从指针开始用几个元素
Go切片增加元素好不好” /> 127 “127”文本文件本质上就是长长的字符串
本质都是二进制的,从二进制伯度看,存的都是某种编码的码点对应的数字。但是人喜欢字符,展示给人看得时候,应用正确的编码表来解营些码点,找到码点对应的字符显示到屏幕,打印到纸张len对于字符串返回的是占用的字节数
虽然可以看做是字符组成的有序序列,但从类型来说就
时间复杂度
0(2)
n表示数据规模o(n) 该时间复杂度和规模有关,n越人,消耗时间越大
文本文件本质上就是长长的字符串
本质都是二进制的,从二进制角度看,存的都是某种编码的码点对应的数字。但是人喜欢字符,展示给人看得时候,应用正确的编码表来解:些码点,找到码点对应的字符显示到屏幕,打印到纸张len对于字竹串返回的是占用的字节数
虽然可以看做是字符组成的有序序列,但从类型来说就不是
时间复杂度
0(2)
n表示数据规模
0(1)1表示常量,是个周定的常数,表示与规模n无关,总是使用周定的计算步骤,对于计算机计算来讲毛毛雨了,顺序表索引定位
这是我们写程序追求极致目标
o(n) 该时间复杂度和规模有关,n越人,消耗时间越人 y=kx
o(n^2) 该时间复杂度和规模有关,n越大,消耗时间越大,y=k(x^2)
0(n^3) 该时间复杂度和规模有关,n越大,消耗时间越大,y=k(x^3) ,比上面的消耗更大,灾难
时间复杂度
0(2)
n表示数据规模
0(1)1表示常量,是个固定的常数,表示与规模n无关,总是使用固定的计算步骤,对于计算机计算来讲毛3这是我们写程序追求极致目标
o(n) 该时间复杂度和规模有关,n越人,消耗时间越人 y=kx有的时候这种只与规模相关的也是我们得追求o(n^2) 该时间复杂度和规模有关,n越大,消耗时间越大,y=k(z^2)2层循环,如果每一层循环都与n相关九九乘法表,2层循环,时间复杂度是多少 ?
for i l~n n
for j 1~n <=i i增加j也增加 j随着规模而增加 n
o(n * n)
一般排序sort都是O(n2),好一点是o(n * gn) 。排序算法很耗时,能不排序就不要排序o(n^3) 该时间复杂度和规模有关,n越大,消耗时间越大,y=k(x^3) ,比上面的消耗更大,灾难3层循环,如果每一层循环都与n相关
数据安全与加解密算法.
1.对称加密
2.非对称加密
3.哈希算法
密码学api
数据结构与算法
1.链表
单向链表
package mainimport "fmt"// 链表中的一个元素type Node struct {Info intNext *Node}// 链表type List struct {Head *NodeLenint}func (list *List) Add(ele int) {node := &Node{Info: ele, Next: nil}if list.Len == 0 {list.Head = node} else {head := list.Headfor i := 1; i < list.Len; i++ {head = head.Next}head.Next = node}list.Len += 1}func (list *List) Travers() {if list.Len == 0 {return}head := list.Headfmt.Println(head.Info)for i := 1; i < list.Len; i++ {head = head.Nextfmt.Println(head.Info)}}func main() {list := List{}list.Add(1)list.Add(8)list.Add(4)list.Add(3)list.Add(5)list.Travers()}
func (list *List) Add(ele int) {node := &Node{Info: ele, Next: nil}if list.Len == 0 {list.Head = nodelist.Tail = node} else {list.Tail.Next = nodelist.Tail = node}list.Len += 1}
链表的应用:LRU缓存淘汰
·LRU(Least Recently Used)最近最少使用思路:缓存的kev放到链表中,头部的元素表示最近刚使用如果命中缓存,从链表中找到对应的key,移到链表头部
如果没命中缓存:
如果缓存容量没超,放入缓存,并把key放到链表头部.
如果超出缓存容量,删除链表尾部元素,再把key放到链表头部
LRU和超时缓存
环
2.栈
3.堆
4.Trie树
堆的应用