-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Go语言动手写Web框架 - Gee第四天 分组控制Group | 极客兔兔 #44
Comments
很好的入门文章!感谢博主! Day4中的Engine定义有一点疑问请教: Engine struct {
*RouterGroup
router *router
groups []*RouterGroup // store all groups
} 这个RouterGroup是Engine的一个属性吗? Go接触不久,还请指教。 |
Wonderful article series, Thanks for sharing the knowledge. |
This is called embeded type in Go |
@evanxg852000 I'm very glad to see your comment. I'm sorry and I'm busy writing the 3rd series, a ORM framework geeorm now. There is a golang version for bolt, named bbolt. I would like to imitate bbolt to implement geebolt, maybe in several weeks. It's a wonderful choice as the 4th, thanks for your suggestion. |
@wzc314 这是 go 中的嵌套类型,类似 Java/Python 等语言的继承。这样 Engine 就可以拥有 RouterGroup 的属性了。 |
感谢博主! |
@201732110125 parent 之前设计是用来拼接 prefix 的,每个 group 只记录自己的部分,最后通过 parent 层层回溯拼接。不过后来改用 |
我认为这里的 RouterGroup 应该嵌套 Engine 而不是反过来,gee.New() 的时候初始化一个 Engine,然后返回一个持有自己的 RouterGroup 就 OK。当然差别也不是特别大,不过从面向对象的角度舒服一点。 func New() *RouterGroup {
engine := &Engine{router: newRouter()}
return &RouterGroup{
Engine: engine,
}
}
func (group *RouterGroup) Group(prefix string) *RouterGroup {
newGroup := &RouterGroup{
prefix: group.prefix + prefix,
Engine: group.Engine,
}
group.Engine.groups = append(group.Engine.groups , newGroup)
return newGroup
} |
@xenv Go语言的嵌套在其他语言中类似于继承,子类必然是比父类有更多的成员变量和方法。RouterGroup 仅仅是负责分组路由,Engine 除了分组路由外,还有很多其他的功能。RouterGroup 继承 Engine 的 |
type RouterGroup struct {
prefix string // 支持叠加
middlewares []HandlerFunc
router *router
}
type Engine struct {
*RouterGroup
}
func New() *Engine {
engine := &Engine{}
engine.RouterGroup = &RouterGroup{router: newRouter()}
return engine
}
func (group *RouterGroup) Group(prefix string) *RouterGroup {
newGroup := &RouterGroup{
prefix: group.prefix + prefix,
router: group.router,
}
return newGroup
} 感觉组合关系这样子好像比较容易理解, |
groups暂时没有作用,是否是后面使用? |
看文章学一半,看评论再学一半/xk |
Engine 和 RouterGroup 是否属于循环嵌套了呢 |
如果只是用前缀当分组的话会不会适用场景不高?我试了下如果是这个场景
那么 v1/say也会执行中间件的代码
刚初学,问题有点多,见谅。 |
type (
) |
|
@sunanzhi 这个就看如何去设计了,前缀区分一般是比较好的方式。比如 对一个博客系统来说, 特别是 Restful API,以资源为中心的 URL 设计,通过前缀做不同业务的区分更为明显,不同前缀代表不同类型的资源。 |
请教一下: 1、能不能在路由的前缀树节点中直接记录分组以及中间件函数呢? 2、另外,我觉得路由的 大概这样: // router.go
type router struct {
root *node
} // trie.go
type node struct {
pattern string
part string
children []*node
isWild bool
isGroup bool
middlewares []HandlerFunc
handlers map[string]HandlerFunc
} |
如果去掉parent,在一个group中再创建一个group怎么办? |
没错没错 |
@fishjar 你的想法是没问题的,当前的这种实现,前缀树解耦得比较好,功能比较单一,容易替换为其他的前缀树实现。Gin 这部分一开始也是利用了第三方实现,后来替换为自己的。 |
@echomuof 再创建子 group 的话,用当前 group 的 prefix 拼接应该就 OK 。 |
@xlban163 哈哈,也感谢你的评论。 |
|
这里RouterGroup和Engine是循环引用吗? 把GET函数中的group.addRoute("GET", pattern, handler) 导致生成的prefix是空字符串,请问这是为什么呢?理论上group指针的prefix应该是有值的,小白求教 |
调用 |
👍解答好详细,受教了。
Lavch <notifications@github.com> 于2021年2月6日周六 下午10:55写道:
… @YellowPure <https://github.com/YellowPure>
这里RouterGroup和Engine是循环引用吗?
在写的时候犯了个错误
把GET函数中的group.addRoute("GET", pattern, handler)
写成了group.engine.addRoute("GET", pattern, handler)
导致生成的prefix是空字符串,请问这是为什么呢?理论上group指针的prefix应该是有值的,小白求教
调用group.engine.addRoute
时,使用的是RouterGroup里面的engine结构从RouterGroup继承的addRoute方法,也就是说addRoute的作用对象是engine里面的RouteGroup指针指向的group变量。
观察函数gee.Group
可以发现,当创建一个新的RouterGroup变量时,该变量内的engine结构实际上等于上一个group内的engine,而上一个engine内的RouterGroup指针指向的的group变量的prefix并没有加上当前Group函数传入的prefix,所以当你调用
group.engine.addRoute时,得到的prefix实际上是调用gee.Group函数得到新的group之前的prefix。在给出的demo里,自然v1.engine.RouterGroup.prefix
== ""
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#44 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABN2XRU2C3UJJKBJ5LSFGC3S5VJ5NANCNFSM4ISW2NUQ>
.
|
有个问题,请问engine的结构体中为什么要包含RouterGroup,是做什么用的? |
|
因为你New出来的实例中包含Group对象,在调用engine下的group也就会执行到这个get方法 |
感觉可以把Engine和RouterGroup合并为一个类型,比如叫做"Dispatcher"之类的
|
我也想知道这个问题 |
curl "http://localhost:9999/v2/hello/geektutu" 结果应该是: |
我也想知道 |
不知道算不算嵌套,Engine算是根Group,里面包含一个groups队列,包含多个分组,每个group里面相当于有一个engine的指针 |
我猜你应该想说子类继承父类,子类继承子类这种模式。但实际上Engine本身是指针,它本身继承了RouterGroup, RouterGroup右包含一个engine成员,你可以理解为双向链表。 |
v1 := r.Group("/v1")
{
v1.GET("/", func(c *gee.Context) {
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
})
v1.GET("/hello", func(c *gee.Context) {
// expect /hello?name=geektutu
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
})
} 这里的大花括号是出于可读性设计的,与Group无关。 |
因为Engine继承了RouterGroup |
RouterGroup实现了Group方法,而Engine 拥有 RouterGroup,那RouterGroup不论保不保存Engine的指针,RouterGroup和Engine都可以添加路由吧 |
感觉你这样写更好理解一些 |
all groups share a Engine instance应该修改为all groups share an Engine instance |
首先,非常感谢大神写的教程,受益匪浅,学习到了很多,非常感谢,已打赏。通过阅读此章节,我发现关于分组的这块是比较绕的,有点难理解,在此我提出一些我觉得更好的优化建议
基于以上的职责模块划分,这里贴出我觉得可以改进的模块 group.go package gee
import (
"log"
)
type RouterGroup struct {
*router
prefix string
parent *RouterGroup
middlewares []*HandlerFunc
}
// 每一个路由的路径肯定是有根的, 那么可以创建一个默认的根路由分组,新加分组必定是基于根路由分组进行新增的
func newRootGroup() *RouterGroup {
return &RouterGroup{
prefix: "",
router: NewRouter(),
}
}
// 所有分组已经路由相关的管理操作的代码,不应该放置到gee.go
func (group *RouterGroup) Group(prefix string) *RouterGroup {
prefix = group.prefix + prefix
newGroup := &RouterGroup{
prefix: prefix,
parent: group,
router: group.router,
}
return newGroup
}
// 这里类似面向对象编程一样重写router.addRoute
func (group *RouterGroup) addRoute(method string, pattern string, handler HandlerFunc) {
pattern = group.prefix + pattern
log.Printf("Route %4s - %s\n", method, pattern)
// 调用父类的addRoute
group.router.addRoute(method, pattern, handler)
}
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
group.addRouter("GET", pattern, handler)
}
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
group.addRouter("POST", pattern, handler)
} gee.go package gee
import "net/http"
type Engine struct {
*RouterGroup // 可以看做是继承底层模块所拥有的能力
groups []*RouterGroup
}
func New() *Engine {
group := newRootGroup()
engine := &Engine{
RouterGroup: group,
groups: []*RouterGroup{group},
}
return engine
}
// engine想知道自己创建了多少个分组, 这里就应该由它自己来进行统计, 这是engine的职责, 而不是RouterGroup的
func (e *Engine) Group(prefix string) *RouterGroup {
group := e.RouterGroup.Group(prefix)
e.groups = append(e.groups, group)
return group
}
func (e *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, e)
}
func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := newContext(w, req)
e.handle(c) // 使用底层模块提供的能力
} |
RouterGroup里面为什么需要*Engine呀,感觉没啥用呀 |
GroupRouter 通过 engine 实例,将自身的路由注册到 handlers 里。 func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
pattern := group.prefix + comp
log.Printf("Route %4s - %s", method, pattern)
// 这里
group.engine.router.addRoute(method, pattern, handler)
} |
中的engine := group.engine是否可以去除而直接使用group.engine呢? |
实现嵌套路由 func (r *RouterGroup) AddRouter(method, comp string, handler HandlerFunc) {
var prefixs []string
this := r
for true {
if this.prefix == "" {
break
}
prefixs = append(prefixs, this.prefix)
this = this.parent
}
prefix := ""
for i := len(prefixs) - 1; i >= 0; i-- {
prefix += prefixs[i]
}
pattern := prefix + comp
fmt.Println(pattern)
r.engine.router.addRouter(method, pattern, handler)
} |
吸收各位大佬的精华,写了一个自己的。
group.go
|
引用了之后RouterGroup才可以使用Engine的功能属性呀,比如 group.engine.router.addRouter() |
|
这节少说很多东西,如果不去看源码,下节肯定一脸懵逼 |
配合chatgpt使用还是比较好的,直接把新加的代码块放进去问,会一句一句的回答 |
这一小节个人认为,添加组实际上是在group的基础上再到组prefix,实际上是在进行插入前缀树,可以根据当前找到gropu.prefix然后在进行拼接,进行查找是否存在该请求路径。但是在这一小块有点问题 |
萌新提问两点 问题一
上面代码中第四行(注释行)是否可以改写成第五行,搞不明白初始化时在groups中加入RouterGroup的意义。 问题二 既然Engine继承了RouterGroup的方法,是否可以删除Engine自身的GET与POST方法,因为即使在不使用分组的情况下效果也是一样的 |
我觉得你这个写的最好 |
问题一: 问题二: |
对于问题二,不需要删除Engine自身的GET与POST方法,虽然逻辑上是继承,但通过Engine和RouterGroup来创建路由、回调本身就是两个行为,而且这两个行为最后都是将路由注册到路由前缀树上 |
|
https://geektutu.com/post/gee-day4.html
7天用 Go语言 从零实现Web框架教程(7 days implement golang web framework from scratch tutorial),用 Go语言/golang 动手写Web框架,从零实现一个Web框架,以 Gin 为原型从零设计一个Web框架。本文介绍了分组控制(Group Control)的意义,以及嵌套分组路由的实现。
The text was updated successfully, but these errors were encountered: