链表
环形链表#如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
12345678910111213141516171819func detectCycle(head *ListNode) *ListNode { slow, fast := head, head for fast != nil { slow = slow.Next if fast.Next == nil { return nil } fast = fast.Next.Next if fast == slow { p := head for p != slow ...
开闭原则
开闭原则#
类的改动是通过增加代码进行的,而不是修改源代码
这个非常简单
就是通过增加结构体,增加代码量来提高代码逻辑性
假设现在 很多人每个人有不同的职业:
1234567891011121314151617181920type People struct{}func (p *People) Teacher() { fmt.Println("this people is a teacher")}func (p *People) Student() { fmt.Println("this people is a student")}func (p *People) Driver() { fmt.Println("this people is a driver")}func main() { p := &People{} p.Teacher() p.Student() p.Driver()}
现在我 ...
单一职责原则
单一职责原则#
类的职责单一,对外只提供一种功能,引起类的变化的原因应该只有一个
这个原则很好理解,也就是 逻辑上的单一性保证逻辑清晰
下面有一个案例,我们有两个穿衣服方式
工作穿衣服
逛街穿衣服
12345678910111213141516171819202122232425262728293031package mainimport "fmt"// 穿衣服的方式type Clothes struct{}// 工作穿衣服func (c *Clothes) Work() { fmt.Println("工作的装扮")}func (c *Clothes) OnShop() { fmt.Println("购物的装扮")}func main() { c := &Clothes{} fmt.Println("工作中......") c.Work() fmt.Println(&q ...
依赖倒转原则
依赖倒转原则#Dependence Inversion Principle, DlP
高层模块不应该依赖低层模块,二者都应该依赖其抽象
抽象不应该依赖细节;细节应该依赖抽象 == 依赖抽象而不是依赖于具体的实现
底层模块
可以理解为 实现层,也就是轮子
高层模块
可以理解为 业务逻辑层,也就是车子,车子需要轮子建造起来
依赖倒转
也就是会在业务逻辑层和实现层之间抽离出一个抽象层、
业务逻辑层向下依赖于抽象层,实现层线上依赖于抽象层,也就实现了依赖倒转的模样
学习资料:
bilibili 刘丹冰 + 100个Go语言错误
现在我们有个业务场景:
实际操作:#现在有司机: 张三李四;汽车: 宝马,奔驰,
然后 - 张三开奔驰 - 李四开宝马
原代码:
1234567891011121314151617181920212223242526272829303132333435363738394041424344package mainimport "fmt"type Benz struct{}func (b *B ...
Go语言典型错误
引言#100个Go语言典型错误
mistakes#
init#
init 会在包初始化时引入,因此可以通过导入副作用的方式初始化init
1_ "github.echin.xxxxx"
不适合使用 init 的三种情况
init 会限制错误管理,因为他只能使用 panic
全局变量管理管理,因为init的初始化是基于包名字母顺序来实现的,且这个全局变量依赖随时可以改变,一般通过封装变量实现
测试复杂度的增加,这个真恶心,详见助手业务的一堆init
init 一般用于 静态数据 的初始化
使用webHook实现CD
#webhook is a lightweight configurable tool written in Go, that allows you to easily create HTTP endpoints (hooks) on your server, which you can use to execute configured commands. You can also pass data from the HTTP request (such as headers, payload or query variables) to your commands. webhook also allows you to specify rules which have to be satisfied in order for the hook to be triggered.
大概意思就是 webHook 会在服务器启动一个端口使用webHook服务,然后你可以配置以及设定rule
思路#使用WebHook实现CD的思路:
我们推送代码到github Action,github ...
Oauth
今天Any给我讲了一下助手的Oauth的逻辑,突然对Oauth茅塞顿开
先白嫖一张图片过来
现在我们模拟一个场景,就是我们使用助手作为授权服务器来访问上课啦这个第三方应用
上课啦 先会将 redirectId state(随机生成) clientId(事先在助手服务器上有绑定) 发给助手服务器
助手 收到 这些参数后就会随机生成一个 code 然后重定向到 hduhelp.com/active 页面
在 hduhelp.com/active 页面我们主要用于激活这个授权码,就是会跳出一个登录页面,让用户登录,生成一个token,然后将token-code-state 绑定在一起存到数据库中
然后因为 Oauth2.0 的具体格式原因,助手会 query.add(state) \ query.add(code) \ clientId \ c.redirect(redirectId) 到上课啦的重定向页面,上课啦会校验 state 分析途中有没有被修改
然后 上课啦 会把 code + state + clientId + redirectUrl 重新发给助手
...
k8s部署
引言#一直想要学会k8s,但是事实上来说学习这个技术并不是靠bilibili的教学就能够学会的,更何况很多时候都会忘记,暑假时候我看完了B站的课,但有种理论知识会了实际不会的无力感,同时更有种知识一点点逝去的害怕,于是在强哥的支持下(白嫖服务器,白嫖域名😍😍),完成了k8s的部署
同时我这一套配置可是any亲传,后继有人呐……
项目原仓库
步骤#
使用 Dockerfile 打包镜像并 push 到 dockerHub 上
部署 mysql\pgsql\redis 这些我的应用所需要的依赖
拉取刚刚提交的镜像并启动一个 pod
暴露我的端口并让外界所访问
实操#首先需要下载 Lens 和 Termius 以及一个文件夹,后续的一切操作都在这两个部分操作
最终的目录应该是这样的:#
这个是本地文件夹下的目录,然后会在 Lens 操作生成Pod,很好用的(等会再说)
我的Dockerfile:#123456789101112131415161718192021222324252627FROM golang:1.22 AS builderCOPY . /buildWORKDIR / ...
装饰器模式
装饰器模式#
装饰器模式可以在不修改原有对象的基础上,通过创建一个包装对象来扩展其功能。这种模式创建了一个装饰类,用来包装原有类,并在保持原类方法签名完整性的前提下提供了额外的功能。
装饰器模式的优点:
扩展性:可以在不修改原有对象代码的情况下,通过装饰类来扩展其功能。
灵活性:可以动态地为对象添加功能。
符合开闭原则:对扩展开放,对修改封闭。
引入#现在我们有这么一个代码:
1234567891011121314151617181920212223func HelloWorld(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("Hello, world!"))}func HowAreYour(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]by ...
函数选项模式
函数选项模式#
函数选项模式是一种在Go语言中常用的设计模式,它允许函数调用者通过一系列可选参数来配置对象。这种模式特别适用于初始化时需要大量配置参数的情况,它避免了长参数列表的问题,并提供了一种更清晰、更灵活的方式来设置对象的状态。
优点:
减少参数列表:避免函数参数过多,提高代码的可读性。
提供默认值:可以为对象提供一组合理的默认值。
灵活性:调用者可以只提供他们关心的配置项。
可扩展性:可以轻松添加新的配置选项,而不影响现有代码。
引入#一般我们初始化函数的时候:
12345678910111213141516171819202122type Server struct { Addr string Port int ReadTimeout time.Duration WriteTimeout time.Duration Timeout time.Duration}func NewServer(addr string, port int, readTimeout, writeTimeout, timeout ti ...