Go Gin源码学习(五)

大二小的宝 · · 931 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Gin路由主要流程实现

经过上一篇的学习笔记,我们已经知道了Gin router的主要流程。但是我们看到代码和方法体总体很长,其中大部分是参数路由的判断。这些零散的小逻辑,让我们阅读源码的时候更难理解了一些。但是其实基数树的逻辑兵没有这么的复杂,所以我们还是按照老规矩,自己实现以下这个简单的基数树值包含主流程。代码如下:

package mygin

import "fmt"

type Trees map[string]*node

type node struct {
    path     string
    indices  string
    children []*node
    handlers HandlerList
}

func (n *node) addRoute(path string, handlers HandlerList) {
    if len(n.path) > 0 || len(n.children) > 0 {
    walk:
        for {
            //找到相等的index
            i := 0
            max := min(len(path), len(n.path))
            for max > i && path[i] == n.path[i] {
                i++
            }
            //需要把原来的作为子node放到新node中
            if i < len(n.path) {
                //新建node
                child := node{
                    path:     n.path[i:],
                    indices:  n.indices,
                    handlers: n.handlers,
                    children: n.children,
                }

                n.children = []*node{&child}
                n.indices = string([]byte{n.path[i]})
                n.path = path[:i]
                n.handlers = nil
            }
            // 判断子节点如果有相同开头的字符 则从新跳入循环
            if i < len(path) {
                c := path[i]
                for index := 0; index < len(n.indices); index++ {
                    if c == n.indices[index] {
                        n = n.children[index]
                        path = path[i:]
                        continue walk
                    }
                }

                //把新请求的path加入到router中
                n.insertChild(path[i:], path, handlers, i)
                return
            }
            return
        }
    } else {
        //如果为空
        n.path = path
        n.handlers = handlers
    }
}

func (n *node) insertChild(path, fullPath string, handlers HandlerList, index int) {
    child := node{}
    child.handlers = handlers
    child.indices = ""
    child.path = path
    n.indices += string([]byte{fullPath[index]})
    n.children = append(n.children, &child)
}

func min(a, b int) int {
    if a > b {
        return b
    }

    return a
}

func (n *node) getValue(path string) (handlers HandlerList) {
    index := 1
walk:
    for {
        fmt.Println("loop num: ", index)
        if len(path) > len(n.path) {
            path = path[len(n.path):]
            c := path[0]
            for i := 0; i < len(n.indices); i++ {
                if c == n.indices[i] {
                    n = n.children[i]
                    index++
                    goto walk
                }
            }
        } else if len(path) == len(n.path) {
            handlers = n.handlers
            return
        }
    }
}

总结

上面的代码已经不需要太多的注释了,去掉了参数节点的代码整个流程已经很明确了。

结束语

Gin的源码学习和分析已经全部结束了。其实对于Gin框架源码的分析已经有了很多文章,但是如果在学习的同时自己也简单的模仿和实现一下这些功能对于我们理解就更有帮助。
Gin是一个十分轻巧http框架,代码也十分的简介和清楚。实现也有一些亮点,我觉得很适合新手对于go源码学习和分析的入门框架。希望这5篇文章能对在学习go中的人有一些帮助。


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:大二小的宝

查看原文:Go Gin源码学习(五)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

931 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传