Go Gin源碼學習(五) 基數樹自我實現

Gin路由主要流程實現

通過上一篇的學習筆記,咱們已經知道了Gin router的主要流程。可是咱們看到代碼和方法體整體很長,其中大部分是參數路由的判斷。這些零散的小邏輯,讓咱們閱讀源碼的時候更難理解了一些。可是其實基數樹的邏輯兵沒有這麼的複雜,因此咱們仍是按照老規矩,本身實現如下這個簡單的基數樹值包含主流程。代碼以下:node

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
        }
    }
}

總結

上面的代碼已經不須要太多的註釋了,去掉了參數節點的代碼整個流程已經很明確了。app

結束語

Gin的源碼學習和分析已經所有結束了。其實對於Gin框架源碼的分析已經有了不少文章,可是若是在學習的同時本身也簡單的模仿和實現一下這些功能對於咱們理解就更有幫助。
Gin是一個十分輕巧http框架,代碼也十分的簡介和清楚。實現也有一些亮點,我以爲很適合新手對於go源碼學習和分析的入門框架。但願這5篇文章能對在學習go中的人有一些幫助。框架

相關文章
相關標籤/搜索