2026-01-25
go
0

记录对于gin源码中insertChild的理解

go
// 使用insertChild是在叶子节点或者空root节点才使用 // 同时,将path视为一部分可能的静态+后部分的通配符段 func (n *node) insertChild(path, fullpath string) { // 对于一个节点插入path,分为是通配符节点还是静态节点 wildslice, i, vaild := findWild(path) // i 小于0 就是没有通配符,所以使用静态处理即可 if i < 0 { n.path = path n.fullpath = fullpath return } // 下面对于有通配符进行处理 for { if !vaild { panic("only one wildcard per path segment is allowed." + wildslice + "is not allowed.") } if len(wildslice) < 2 { panic("wildslice must be named." + fullpath) } // 对冒号通配符进行处理 if wildslice[0] == ':' { if i > 0 { n.path = path[:i] path = path[i:] } child := &node{ nType: param, path: wildslice, fullpath: fullpath, } n.addChild(child) n.wildChild = true n = child if len(wildslice) < len(path) { path = path[len(wildslice):] child := &node{ fullpath: fullpath, } n.addChild(child) n = child continue } return } // 对星号通配符进行处理 // 如果*通配符不是最后一段,报错 if i+len(wildslice) != len(path) { panic("catch-all route must be last in path." + fullpath) } // 如果当前节点已经有path,并且最后一位是/符号,即/static/pic/模式 // 注意,如果path的最后一位是 / 符号,那么可能后面会有其它的子节点 // 即使没有子节点,但是这种路径很危险,所以当n.path > 0 并且最后一位是 / 符号时,就报错 // 如果有子节点,那么就和*通配符冲突了,更加错误 if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { pathSeg := "" if len(n.children) != 0 { pathSeg, _, _ = strings.Cut(n.children[0].path, "/") } panic("catch-all wildcard '" + path + "' in new path '" + fullpath + "' conflicts with existing path segment '" + pathSeg + "' in existing prefix '" + n.path + pathSeg + "'") } i-- if i < 0 || path[i] != '/' { panic("no '/' before catch-all in path:" + fullpath) } // 星号通配符节点分为两个节点表示 n.path = path[:i] child := &node{ wildChild: true, nType: catchAll, fullpath: fullpath, } n.addChild(child) n = child child = &node{ path: path[i:], nType: catchAll, fullpath: fullpath, } n.children = []*node{child} return } }