当前位置: 首页 > news >正文

Go第三方框架--gin框架(一)

序言

Gin框架作为go语言使用最多的web框架,以其快速的响应速度和对复杂http路由配置的支持受到程序员和媛们的喜爱,几乎统治了web市场。但作为一名合格的程序员,要知其然更要知其所以然,不然八股文背的也没有啥意思。本着这个原则鄙人打算站在前人的大腿根上从头到尾梳理下Gin的执行流程,主要涉及两大部分:1. 服务器的建立(重点是:Gin是怎么处理和存储各种不同的路由路径和请求函数体的);2. 客户端的连接(主要涉及根据路由寻找对应函数体来执行具体业务逻辑)

1. gn框架的诞生

1.1 go 原生web框架

go 原生的 web框架 在 net/http 包里,因不是本文重点,所以只简要介绍。
net/http 主要采用 map的原理来 存储 路径和handler 其中 key 是 路径 value 是 handler ,如下图的代码

# ServeMux是一个HTTP请求多路复用器。其中 m 保存了 其请求路径和handler的映射关系。
type ServeMux struct {mu    sync.RWMutexm     map[string]muxEntryes    []muxEntry // slice of entries sorted from longest to shortest.hosts bool       // whether any patterns contain hostnames
}
type muxEntry struct {h       Handlerpattern string
}
func TestHttp(t *testing.T) {// 创建路由器mux := http.NewServeMux()// 设置路由规则mux.HandleFunc("/hello", hello)mux.HandleFunc("/hello/hell", hello2)mux.HandleFunc("/hel/ww", hello2)mux.HandleFunc("/helw/*ww", hello2)// 创建服务器server := &http.Server{Addr:         Addr,WriteTimeout: time.Second * 3, //超时时间Handler:      mux,             //路由规则  }// 监听端口并提供服务log.Println("Starting httpserver at " + Addr)err := server.ListenAndServe()if err != nil {panic(err)return}log.Fatal()
}func hello(w http.ResponseWriter, r *http.Request) {time.Sleep(1 * time.Second)w.Write([]byte("bye bye ,this is httpServer"))
}func hello2(w http.ResponseWriter, r *http.Request) {time.Sleep(1 * time.Second)w.Write([]byte("bye bye ,this is httpServer"))
}

其 建立的 map如下:
在这里插入图片描述
可以看出其确实建立了一个 map来存储 路径和handler的映射关系。采用map形式 查找的速度也比较的块。但是为啥还要采用Gin框架呢。
我们来简要梳理下我们程序员在工作过程中需要啥样的web框架吧

  1. 需要一个可以处理通配符的框架,比如这种: aa/dd* 虽然我(net/http)不支持但是我 速度快啊
  2. 需要可以处理中间件的框架 比如 对日志的处理等 虽然我(net/http)不支持但是我 速度快啊
  3. 需要 支持分组的框架 比如 v1 v2这种不同的版本 虽然我(net/http)不支持但是我 速度快啊

目前看来 net/http不适合这种复杂场景的业务逻辑 当然 Google go开发组 目的只是提供一个简小的web框架,设计目标是简单和通用。go开发组 当然也想到了 要利用开源的优势为各路大神提供大显神通的机会。问题是怎么接入呢,现实世界和虚拟世界的连接入口是 二维码。那gin框架如何接入 net/http 呢,也就是如何在重新利用它的其他功能的情况下,再进行扩展呢 你当然能想到了 这就是 interface 接口。

net/http框架中 确实是 通过实现接口来 进行 路由查找 并找到要执行的 hanlder(例如 上述代码中的hello),这样路由建立模块和路由寻址查找handler模块就可以通过不同实现来形成不同的第三方框架。建立路由模块是第三方包独自完成,而路由寻址查找模块主要是实现了 如下接口:

type Handler interface {ServeHTTP(ResponseWriter, *Request)
}

这样第三方框架 就可以复用net/http 的大部分功能(包括最重要的 epoll多路复用),并通过实现 ServeHTTP 接口 来实现自己的 路由查找模块(ps: 路由建立模块需自己建立 这块功能用不到接口) ,说完了 理论 那我们再来梳理下 net/http 从 建立连接 到 ServeHTTP的调用链,来验证下上述是否是这样的。

1.2 原生 net/http的 调用链

以 TestHttp 这个函数为例,调用入口是 server.ListenAndServe() ,其调用链为

在这里插入图片描述
可以看到 其最终调用到了 ServeHTTP() 这个函数,而所有第三方框架都是实现了 这个函数。这个函数包括 根据req函数中的 url获取 handler(第三方框架提供) 、处理handler和对客户端返回结果三大块的功能。
这样第三方框架就可以 实现ServeHTTP这个函数来 实现对 handler的获取(怎么建立路由结构是第三方框架自己定义)。

1.3 gin等第三方web框架和net/http关系

让我们脱离源码 来梳理下
在这里插入图片描述
可以看到 第三方 框架 主要是头尾两个地方跟 net/http不同 中间还是需要复用net/http代码。后续 讲解会围绕这张流程图展开,其中比较重要的是 圆圈 1、2和3,1 包括 gin 的引擎 engine 其包括建立压缩前缀树的功能并实现了 serverHttp接口 形成了 3,2主要涉及了多路复用技术。
以下的 步骤 2、3、4主要涉及圆圈1 的内容,步骤5 涉及圆圈2 的内容 ,步骤6 涉及圆圈3的内容

2. gin框架简介

2.1 gin框架发展历程

gin 框架早期版本是基于julienschmidt/httprouter 发展而来,julienschmidt/httprouter是一个高性能的http请求器。但是随着gin框架的发展 它逐渐发展出了自己的 路由实现器,实现源码也部分参考 julienschmidt/httprouter 这也就是为什么好多资料都说 gin基于julienschmidt/httprouter 但是你去看它最新的源码却没发现针对 julienschmidt/httprouter的引用。
gin框架之所以运行效率高是因为采用了一种叫 Radix Tree (压缩前缀树)的结构体来存储路由路径,其是一种例如有如下路由:

/aa/bb
/aa/bd
/aa/cc
/ac/dd
/ee/ff

建立压缩前缀树 ,请思考下其建立的树是左边还是右边呢
在这里插入图片描述
gin 框架的路由树的建立 就是一步一步建立如上图所示的 压缩前缀树 ps:真是的树的节点比较复杂 但是大体步骤就是如此
那么压缩前缀树 有啥优点呢 gin 为什么使用这种结构来存储器节点呢 直觉上看 我们可以想到两点 1: 这种树形结构 查找的时间复杂度是时间复杂度为 o(k) ,k是字符串的长度 2: 压缩证明其使用的空间比较少 可以看到 路径中 有 6个a 但是 我们树节点中只有 2个。这只是我们直观看出来的,对不对呢,是否还有其他优点呢?

答案: 对,当然有其他优点,这种树 也可以用来 进行通配符的匹配 例如这种 /aa/bb/* ;还可以快速建立路由分组等。这两种优势不是本文的重点,感兴趣的同学可以自行查阅资料。
既然你说gin 路由使用的是 压缩前缀树,口说无凭 我们来验证下吧 顺便看下建立的是左边还是右边的压缩前缀树

2.2 gin框架的使用

下面示例代码为(本文后续围绕下面例子展开代码讲解):

func TestGin(t *testing.T) {// 创建一个默认的路由引擎r := gin.Default()// 当客户端以GET方法请求路径时,会执行后面的匿名函数r.GET("/aa/bb", func(c *gin.Context) { c.JSON(200, gin.H{"route path ": "/aa/bb",}) })r.GET("/aa/bd", func(c *gin.Context) { c.JSON(200, gin.H{"route path ": "/aa/bd",}) })r.GET("/aa/cc", func(c *gin.Context) { c.JSON(200, gin.H{"route path ": "/aa/cc",}) })r.GET("/ac/dd", func(c *gin.Context) { c.JSON(200, gin.H{"route path ": "/ac/dd",}) })r.GET("/ee/ff", func(c *gin.Context) { c.JSON(200, gin.H{"route path ": "/ee/ff",}) })// 以上操作 **主要 涉及 圆圈 1**// 启动HTTP服务,默认在0.0.0.0:8080启动服务  **涉及 net/http 框架处理主逻辑 内部 主要 调用 net/http 包**r.Run()}

对上述代码 debugger 可以得到 r 这个参数的 实例 实力分析如下 其中 压缩前缀树的节点node结构体的结构如下:

type node struct {path      stringindices   stringwildChild boolnType     nodeTypepriority  uint32children  []*node // child nodes, at most 1 :param style node at the end of the arrayhandlers  HandlersChainfullPath  string
}

现在只需关注node节点的 path 和 children 这两个参数 node结构体详情会在后续步骤介绍
2.2.1 父节点
在这里插入图片描述
可以看到 父节点 path == “/” 且有两个孩子节点

2.2.2 第二层节点

在这里插入图片描述
可以看到 第二层 节点 左边节点 path==“a” 孩子个数为2 ;右边节点 pah 是 “ee/ff” 这里就是将节点进行了压缩 ee 和 ff 不用再拆分了。因为 ff是ee的唯一的一个孩子节点 因为寻址路径唯一 所以可以向上合并,以便节省空间。

2.2.3 第三层节点

在这里插入图片描述
可以看到 左边节点 path==“a/” 孩子节点个数为2 ;右边节点 path==“c/dd”(压缩了) 孩子节点为空

2.2.4 第四层节点
在这里插入图片描述
可以看到 左边 节点 path=“b” ,其有两个孩子节点;右边节点 path=“cc” 其没有孩子节点

2.2.5 第五层 节点

在这里插入图片描述
可以看到 左边节点 path==“b” 无孩子节点 ;右边节点 path==“d” 无孩子节点

到这里我们可以看出来其确实是建立了一颗 压缩前缀树。总结下来就是: 1. 孩子节点必须大于1(否则应向上合并)2: 压缩有两层含义 第一层将 路由里面 重复的路径 进行压缩 例如 字母a 压缩后就剩2个;第二层 一个节点有一个子节点时 向上兼并 压缩空间
所以建立的前缀树是 右边的。

r.run()执行后 在浏览器输入 路径 就可以看到 对应的函数被执行(注意:默认端口是8080)结果 如图 这边主要涉及 圆圈 2–>3
在这里插入图片描述

2.3 gin框架的执行过程

梳理完毕 压缩前缀树的建立 那现在开始我们梳理下 整个 gin框架的流程图 其实主要是围绕 构建的压缩前缀树展开的 ,我个人比较愿意先学习框架使用,然后再进入细节,这样有一个提纲挈领的抓手,我们就知道这些细节在整体脉络中的位置,不至于陷进去失去了方向感。

通过1.3的图可以看到 gin 框架 大概 分为 三大部分

  1. 创建 压缩前缀树 并且 将 路由 对应的节点 按照规则 插入树节点 ---- 步骤一(圆圈1)
  2. 运行 引擎 建立 对tcp套接字的监听 这里采用多路复用技术 进行阻塞 等待链接到来 ---- 步骤二
  3. 浏览器 输入 url 进行客户端请求 这时 唤醒阻塞的程序 从圆圈2 按照箭头执行顺序 一直执行到 圆圈3,然后在圆圈3 中遍历 压缩前缀树 找到对应的 handler (对于路径 :/aa/bd 其 handler 为:func(c *gin.Context) { c.JSON(200, gin.H{"route path ": “/aa/bd”}) }) 执行后 返回结果 ---- 步骤三

3. gn框架源码–四种重要的结构体

框架一般都会采用面向对象的方式来构建,而面向对象中最重要的核心就是结构体。gin框架四种重要的结构体 分别是 Engine/RouterGroup/Node/context ,其中Engine 包含了 RouteGroup和Node 是gin框架的引擎结构体 ;Node是压缩前缀树的树节点,用来保存 压缩路径和handler,在2.2.1----2.2.5中已经做过简要介绍 ;Context 结构体官方介绍是 gin最重要的结构体 ,它允许我们在中间件之间传递变量,管理流,处理 request 请求体和 respose 响应体。可以说 gin 框架基本上是围绕着这四个结构体来操作的。

3.1 Engine 结构体
type Engine struct {RouterGroup   // 路由组 ...... //  这里为了使得文章简短 一些本文讲解没用到的 属性 没有列举 感兴趣的可以自己研究下 // UseH2C enable h2c support.UseH2C bool// ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.ContextWithFallback booldelims           render.DelimssecureJSONPrefix stringHTMLRender       render.HTMLRenderFuncMap          template.FuncMapallNoRoute       HandlersChainallNoMethod      HandlersChainnoRoute          HandlersChainnoMethod         HandlersChainpool             sync.Pool   // 这个池化技术 用来存储 Context结构体。 它是 gin框架很重要的结构体 主要用来 处理 request和 respose 请求trees            methodTrees   // 方法树 针对 Get/Post/Delete 等不同请求 都生成一个树 9种请求 9种树 但实现原理都是相同的 本文只介绍 Get方法,其 包含了 Node 结构体maxParams        uint16maxSections      uint16trustedProxies   []stringtrustedCIDRs     []*net.IPNet
}

Engine 结构体 是 gin 框架的入口,其包含了许多属性 但对于 我们学习jin框架核心执行逻辑来说,只需要知道 RouterGroup/pool/trees 这三个就行了

3.2 RouteGroup结构体
type RouterGroup struct {Handlers HandlersChain   // 需要处理的 handler 链,一般是 默认hanlder(例如 处理 logger和panic的handlewr)+ group组的中间件handler(例如 鉴权等)+ 用户 注册的 handlerbasePath string  // 组的基本路径engine   *Engine // gin 框架 引擎root     bool // 跟节点
}

RouterGroup 主要是用来 对路由进行操作的,包括对post/get等方法的处理。

3.3 Node 结构体
type node struct {path      string  // 节点路劲indices   string // 其子节点的 path的第一个单词 组成的 字符串 用来快速定位路径寻址时 是否走此孩子节点wildChild boolnType     nodeType // 节点类型priority  uint32  // 优先级 从左往右 越左侧 优先级越大 优先从左边开始 说明 左边的 重复的路径前缀比较多 同层其优先级越高 子节点越多 ,一般情况下 priority等于其直属孩子节点个数,且如果其直属孩子节点为一个 或者 为空,其 优先级 为 1children  []*node // child nodes, at most 1 :param style node at the end of the arrayhandlers  HandlersChain  // 处理器 存储 节点 handler 链 fullPath  string // 全路径 fullPath 
}

node 是压缩前缀树子节点,是gin框架之所以速度快的核心原因,也是我们本篇文章重点需要介绍和理解的结构体。
对于节点属性的理解 可以对照着 标题 2.21----2.2.5来理解

3.4 context 结构体
type Context struct {writermem responseWriterRequest   *http.RequestWriter    ResponseWriterParams   Paramshandlers HandlersChainindex    int8fullPath stringengine       *Engineparams       *ParamsskippedNodes *[]skippedNode// This mutex protects Keys map.mu sync.RWMutex// Keys is a key/value pair exclusively for the context of each request.Keys map[string]any// Errors is a list of errors attached to all the handlers/middlewares who used this context.Errors errorMsgs// Accepted defines a list of manually accepted formats for content negotiation.Accepted []string// queryCache caches the query result from c.Request.URL.Query().queryCache url.Values// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,// or PUT body parameters.formCache url.Values// SameSite allows a server to define a cookie attribute making it impossible for// the browser to send this cookie along with cross-site requests.sameSite http.SameSite
}

context 是gin框架最重要的结构体 其包含了对 请求 和 响应的 处理逻辑,可以在中间件之间传递数据流。因不是本文的理解gin框架的需要用到的结构体,暂不做过多介绍,请自行用谷歌百度一下。

相关文章:

Go第三方框架--gin框架(一)

序言 Gin框架作为go语言使用最多的web框架,以其快速的响应速度和对复杂http路由配置的支持受到程序员和媛们的喜爱,几乎统治了web市场。但作为一名合格的程序员,要知其然更要知其所以然,不然八股文背的也没有啥意思。本着这个原则…...

网络安全——笔记

XSS:跨站脚本(Cross-site scripting) XSS 全称“跨站脚本”,是注入攻击的一种。其特点是不对服务器端造成任何伤害,而是通过一些正常的站内交互途径,例如发布评论,提交含有 JavaScript 的内容文…...

Maven pom.xml配置详解

pom.xml是什么&#xff1f; pom.xml&#xff08;项目对象模型-Project Object Model的缩写&#xff09;是Maven项目的核心配置文件&#xff0c;用于管理项目的依赖、插件、构建配置等。 举例说明&#xff1a;以阿里巴巴的fastjson为例&#xff1a; <?xml version"1.…...

2024深圳国际电线电缆及电源产品展览会

2024深圳国际电线电缆及电源产品展览会 2024 Shenzhen International Coupling, Clutch and Brake Exhibition 时间&#xff1a;2024年08月28-30日 地点&#xff1a;深圳国际会展中心&#xff08;新馆&#xff09; 预订以上展会详询陆先生 I38&#xff08;前三位&#xff…...

如何成功将自己开发的APP上架到应用商店

随着移动应用市场的蓬勃发展&#xff0c;开发一款优秀的APP已成为许多企业和个人的首要选择。然而&#xff0c;成功上架并有效推广APP至关重要。本文将逐步介绍完整的上架流程&#xff0c;包括准备所需材料、注册开发者账户、进行APP备案、提交审核以及上架成功后的推广和维护。…...

Jetson AGX ORIN 配置 FGVC-PIM 神经网络(包含 arm64 下面 torch 和 torchvision 配置内容)

Jetson AGX ORIN 配置 FGVC-PIM 神经网络 文章目录 Jetson AGX ORIN 配置 FGVC-PIM 神经网络配置 ORIN 环境创建 FGVC-PIM 虚拟环境安装 PyTorch安装 torchvision安装其他依赖包 配置 ORIN 环境 首先先配置 ORIN 的环境&#xff0c;可以参考这个链接&#xff1a; Jetson AGX …...

mybatisplus和mybatis兼容问题

Invalid bound statement (not found) 错误 原xml配置 <bean id"sqlSessionFactory" class"org.mybatis.spring.SqlSessionFactoryBean"><property name"mapperLocations" value"classpath:/META-INF/mapper/*.xml"/>&l…...

nodejs安装使用React

1、react安装 首先&#xff0c;确保电脑上具备nodejs环境&#xff0c;之后用 winr 呼出控制台&#xff0c;输入 cmd 命令弹出cmd控制台&#xff08;小黑框&#xff09;之后在默认路径输入如下代码 npm i -g create-react-app //全局安装react环境无需选择特定文件夹安装成功后…...

防御性编程,可能是导致被裁员的更大的原因,别被误导了

裁员与反裁员是当前IT界一个经典的话题&#xff0c;作为打工者的猿人常常讨论了N多的防御性编程&#xff0c;代码不可读、代码不好改、代码深度嵌套、代码留bug等等。 其实防御性编程只会让决策者加速解耦你与业务系统&#xff1a; 1、增加代码走查的环节&#xff08;增加成本…...

Unity与鼠标相关的事件(自己记忆用)

1. OnMouseDown&#xff1a;当用户按下鼠标按钮时调用。 - 参数&#xff1a;MouseEvent&#xff0c;可以用来确定哪个鼠标按钮被按下。 2. OnMouseUp&#xff1a;当用户释放鼠标按钮时调用。 - 参数&#xff1a;MouseEvent&#xff0c;可以用来确定哪个鼠标按钮被释放。…...

模型权重下载方法

下载方法1&#xff1a;git lfs下载 1、在hf-mirror.com中搜索模型&#xff0c;如搜索text2vec-large-chinese&#xff0c; 点击模型进入页面&#xff1a;https://hf-mirror.com/GanymedeNil/text2vec-large-chinese/tree/main 2、git lfs install 3、git clone https://hf-mir…...

JS基础之 数据浅拷贝与深拷贝

一、拷贝背景 JS引用数据类型有两类&#xff1a;基本数据类型和引用数据类型&#xff1b; 基本类型&#xff1a;String&#xff0c;Number&#xff0c;Boolean&#xff0c;Null&#xff0c;Undefined&#xff0c;symbol这6种基本数据类型它们是直接按值存放的&#xff0c;所以…...

FFmpeg开发笔记(十四)音频重采样的缓存

FFmpeg在很多地方都运用了缓存机制&#xff0c;比如《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“3.3.2 对视频流重新编码”介绍了编解码的数据缓存&#xff0c;不单是视频编码过程和视频解码过程有缓存&#xff0c;甚至连音频重采样都用到了缓存。 也就是说&a…...

详解Python面向对象编程(一)

类和对象 面向过程——怎么做&#xff1f; &#xff08;1&#xff09;把完成某一需求的所有步骤、从头到尾&#xff0c;逐步实现 &#xff08;2&#xff09;根据开发需求&#xff0c;将某些功能独立的代码块封装成一个又一个的函数 &#xff08;3&#xff09;最后完成的代码&a…...

一文带你完整了解Go语言IO基础库

作者 | 百度小程序团队 导读 introduction 对于刚接触Golang学习的同学&#xff0c;估计比较难掌握的知识点之一就是文件IO处理&#xff0c;光在基础库里会发现 golang除了io包提供文件处理外&#xff0c;os包&#xff0c;http包&#xff0c;embed包都有提供类似的处理&#xf…...

Java基于微信小程序的校园请假系统

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

Expert Prompting-引导LLM成为杰出专家

ExpertPrompting: Instructing Large Language Models to be Distinguished Experts 如果适当设计提示&#xff0c;对齐的大型语言模型&#xff08;LLM&#xff09;的回答质量可以显著提高。在本文中&#xff0c;我们提出了ExpertPrompting&#xff0c;以激发LLM作为杰出专家回…...

Element-Plus下拉菜单边框去除教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…...

免费redis可视化工具windows/mac都可以使用,开源免费

官方地址&#xff1a;RedisInsight | The Best Redis GUI github开源地址&#xff1a;GitHub - RedisInsight/RedisDesktopManager Redis Desktop Manager – Redis可视化管理工具、redis图形化管理工具、redis可视化客户端、redis集群管理工具。 官方下载方式 滚动到页面底…...

PHPCMS v9城市分站插件

PHPCMS自带的有多站点功能&#xff0c;但是用过的朋友都知道&#xff0c;自带的多站点功能有很多的不方便之处&#xff0c;例如站点栏目没法公用&#xff0c;每个站点都需要创建模型、每个站点都需要单独添加内容&#xff0c;还有站点必须静态化。如果你内容很多这些功能当然无…...

学习几个地图组件(基于react)

去年开发时用的公司封装的地图组件&#xff0c;挺方便的&#xff0c;但是拓展性不强&#xff0c;所以看看有哪些优秀的开源地图组件吧 1、React Leaflet 介绍&#xff1a;开源的JavaScript库&#xff0c;用于在web上制作交互式地图&#xff0c;允许你使用React组件的方式在应…...

【测试开发学习历程】计算机编程语言

前言&#xff1a; 学习完数据库&#xff0c;我们便要进入到编程语言的内容当中了。 这里先对编程语言写出大致的分类&#xff0c; 在这之后&#xff0c;我们会以Python为重点&#xff0c; 开始测试开发为重点的编程语言学习。 目录 1 计算机编程语言的发展 2 语言的分类…...

动态内存管理-传值调用错题解析

首先我们来看这个错误代码 首先我们看代码逻辑&#xff0c;首先main函数调用test&#xff0c;test接收的是void类型&#xff0c;设置一个指针变量&#xff0c;指向null&#xff0c;传递给get函数&#xff0c;也就是传递一个空指针给getmemory函数&#xff0c;这个函数接收了&a…...

Java特性之设计模式【装饰器模式】

一、装饰器模式 概述 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种类型的设计模式属于结构型模式&#xff0c;它是作为现有的类的一个包装 装饰器模式通过将对象包装在装饰器类中&#xff0c;以…...

Leetcode算法题笔记(2)

目录 图论51. 岛屿数量解法一 52. 腐烂的橘子解法一 53. 课程表解法一 54. 实现 Trie (前缀树)解法一 回溯55. 全排列解法一 56. 子集解法一解法二 57. 电话号码的字母组合解法一 58. 组合总和解法一解法二 59. 括号生成解法一解法二 60. 单词搜索解法一 61. 分割回文串解法一 …...

二手车交易网站|基于JSP技术+ Mysql+Java+ B/S结构的二手车交易网站设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…...

lora-scripts 训练IP形象

CodeWithGPU | 能复现才是好算法CodeWithGPU | GitHub AI算法复现社区&#xff0c;能复现才是好算法https://www.codewithgpu.com/i/Akegarasu/lora-scripts/lora-trainstable-diffusion打造自己的lora模型&#xff08;使用lora-scripts&#xff09;-CSDN博客文章浏览阅读1.1k次…...

Acwing 503. 借教室

Problem: 503. 借教室 文章目录 思路解题方法复杂度Code 思路 这是一个二分查找问题。我们需要找到最大的借教室数量&#xff0c;使得每个教室的借用时间不超过其可用时间。我们可以通过二分查找来找到这个最大的借教室数量。 解题方法 我们首先对所有的借教室请求按照结束时间…...

吴恩达深度学习笔记:浅层神经网络(Shallow neural networks)3.1-3.5

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第三周&#xff1a;浅层神经网络(Shallow neural networks)3.1 神经网络概述&#xff08;Neural Network Overview&#xff09;3.2 神经网络的表示&#xff08;Neural Network Representation…...

Linux设备驱动开发 - 三色LED呼吸灯分析

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 展锐UIS7885呼吸灯介绍呼吸灯调试方法亮蓝灯亮红灯亮绿灯展锐UIS7885呼吸灯DTS配置ump9620 PMIC驱动ump9620中的LED呼吸灯驱动LED的tr…...