上一篇文章简单地介绍了使用golang如何完成内存中的增删改查,其实在实际工作中用处不是很大,旨在帮助大家了解一些golang的一些基本语法,和golang http包的基本使用,如何获取GET和POST两种常用请求的参数,并且留下了一个小疑问,如何获取url中的参数信息,也就是在java中spring mvc强大的参数绑定功能是如何实现的
说明:本文的完整代码地址在本文的末尾,如果写的不对的地方,希望有大神直接打脸批评
本小节可以收获或者可以拓展的知识点如下
- 数据结构Trie的深入学习和使用,并不一定局限于golang,大家可以去LeetCode去看看Trie的问题
- golang中strings的工具类方法的使用,大家可以去看下strings的API
- golang的map使用,希望大家能够熟悉golang最最常用的数据结构map的操作
- golang的”单元测试”的基本使用
例如如下两个URL,这2个url其实就想获取id分别是1和2的用户信息,跟上文中提到的在java的spring mvc的参数绑定是使用RequestMapping注解,value写”/get/user/{id}”,然后在方法入参前面使用PathVariable注解来进行参数绑定,相信熟悉spring web开发的同学,肯定是如数家珍,用起这套也是得心应手,但是在golang原生的http包开发中,这种 通配符 (wildcard)匹配的方式并不是原生支持的,当然也有很多的第三方包支持里如果httprouter,gin,beego等等,但是几乎所有第三包的都是使用Trie这种数据结构来完成的,本小节就来入门这种强大好用,且简单的数据结构Trie
- /get/user/1
- /get/user/2
Trie其实是一种比较常用的数据结构,我们通过自己写一个简单也可能很粗糙的自我实现的Trie数据结构,可以很好地帮助大家快速学习golang的一些基本语法,进一步熟悉golang的代码特点,本文也是一个很好的小练习
什么是Trie
Trie的作用
trie树常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。
本文中所设想构造的URL类型的Trie
其实我们就想构建一个这样的Url Trie,这样我们就可以找到这个树的某个节点,然后这个节点所对应的handler处理,就可以完成我们在spring mvc中完成的功能了
1.没有wildcard的最简单的trie实现,我们首先要用golang定义Trie的数据结构,如下截图所示,我们自定义的Trie叫做UriTrie,里面最重要的属性就是Node这个数据结构,Node这个节点如果没有isLeaf这个属性,其实就是一个map的数据结构,所以还是比较好懂的,如果你仔细思考一下,这也是简单的一个递归结构,map的value还是一个Node,这就变成了一个天然的递归结构了
2.1 Trie里面添加节点Node
添加的节点是一个string类型,举例来说”/user/group/add”类似这种的,我们使用”/”进行切割,将其转换成[“user”,”group”,”add”]的数组,然后从跟map中遍历,如下代码中,你要注意的就是变量”cur”的定义和切换过程,如果是是第一次接触这种数据结构,稍微用笔画一下,你可能就理解了,如果你是大牛,可以指点我这个小菜鸟的不足,最后添加到”add”节点的时候,要把这个node的isLeaf设置为true,表明这是一个完整的节点,也表明”/user/group”这种请求过来的时候,是不会有节点匹配的,因为”group”节点的isLeaf属性不是true,说明在这棵”树”中不存在”/user/group”这个节点
2.2 Trie里面搜索节点Node
搜索的方法就更加简单了,基本上跟add方法一模一样,有区别的在两个地方,一个地方是在下沉递归找数据的时候,当不存在中间节点的时候,就直接返回了,而不是新增一个节点,还有一个是当能找到节点的时候,不能简单的把cur节点返回就可以了,还要返回cur是否是isLeaf节点的属性返回,就就是在add的时候,为什么要加isLeaf这个属性的原因了,还是刚才的例子添加”/user/group/add”之后,在这棵树中查询”/user/group”节点的时候,虽然从数据结构上物理存储上来说的确存在该节点,但是该节点的逻辑属性isLeaf是false,它只是一个过渡节点,没有实际意义
测试
golang也提供了我们很健全的测试机制,golang也提供了和java比较类似的junit的工具,只不过golang是内嵌的,不需要第三方外部依赖,我们先简单地描述一下如何使用golang进行代码测试
1.一般来说是同包测试,例如如下图所示,我们写的数据结构叫做uri_trie.go(注意golang和java不一样,一般不使用驼峰式命名风格),测试类叫做uri_trie_test.go,就是在要测试的go文件名加一个_test的后缀
2.方法都是是Test为开头,注意T必须大写,参数一般是*testing.T类型
这个小节,我们基本上要了60行左右的代码实现了一个很简单的Trie,也写了一个简单的单元测试,稍微上手一下golang的单元测试,不过目前实现的Tire这个并不能满足我们的要求,并不能解决我们之前说的问题,因为并不支持通配符匹配,下一个小节稍微修改一下代码就可以解决我们的需求,还是那句话,如果是新手还是要多写代码,熟能生巧,通过一个个的小练习,就会慢慢成长