记录对于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
}
}