原文链接:[https://ashan.org/archives/932](https://ashan.org/archives/932) 国庆节时,用大约9天时间借助golang重写编写了博客系统的前台部分,由于系统的特殊性,这部分完成后只能说完成了整套系统1/3的功能。十一回来后,又用了大约10天时间,每天写一点,完成了系统余下的两部分内容。由于是第一次用golang开发服务器内容,所以踩得坑不少,这里做一个总结。 ### 函数传值问题 这个问题不算难,一开始看文档的时候已经注意到了,但没太在意。因为很多逻辑代码都是照搬旧版Nodejs版本来写的,所以就更加忽略了这个问题。知道本地命令操作时间略长,我才感觉不对劲。 举一个简单的例子: ``` package main import ( "fmt" "time" ) func main() { _abc() } func _abc() { fmt.Println("start") starttime := time.Now() var data Tt for i := 0; i < 10000; i++ { Set(data) } fmt.Println(time.Since(starttime)) } type Tt struct { Name string Age int Email string Addr string Nickname string } func Set(data Tt) Tt { data.Name = "ashan" data.Age = 32 data.Email = "abc@abc.com" data.Addr = "china" data.Nickname = "ashan" return data } ``` 上面这段代码运行起来需要大约`214.323µs`。在1ms内完成了,我们稍微修改一下代码再来运行一次。 ``` package main import ( "fmt" "time" ) func main() { _abc() } func _abc() { fmt.Println("start") starttime := time.Now() var data Tt for i := 0; i < 10000; i++ { Set(&data) } fmt.Println(time.Since(starttime)) } type Tt struct { Name string Age int Email string Addr string Nickname string } func Set(data *Tt) *Tt { data.Name = "ashan" data.Age = 32 data.Email = "abc@abc.com" data.Addr = "china" data.Nickname = "ashan" return data } func Setint(data *int) *int { *data = 5 + 12*8 return data } ``` 再次运行,耗时约为`50.675µs`。时间相差4到5倍之间。 这个例子告诉我们,函数调用传参的时候`struct `尽量要传递指针。原因很简单,如果不传递指针,在函数内部,会存在自己的作用域,由于域不同,则需要针对传递进来的类型,再次申请内存空间,创建一个值一样的副本,这个操作就相当耗时。 针对这个问题,只能重构修改,目前还没有进行,等待下一个版本优化重构时候在进行调整。 ### import cycle not allowed 问题 这个问题是在项目最后才出现的,当时非常奇怪,为什么会出现“循环引用”问题,最后发现是由于goalng的import包加载机制导致的。 简单解释一下可以立即为,在包A中 import 包B,而包B中 import 包A。当进行编译时,则发生互相递归引用,从而发生问题。 思考良久,如此问题怎样解决会比较好,产生这个问题的原因可能会出现在一下两种情况中: 1. 使用的库存在互相应用的问题 2. 自身模块结构设计存在问题 第一种问题基本属于掉坑了,解决的方法没啥好办法,只能自己想办法调整。 第二种情况可以使用重构来解决,这也是我未来要做的事情。出现这种情况,只能将功能重复的代码作为公用库放到一个独立的包当中,从而避免此类问题发生。 ### 大写与小写 golang算是在语法糖中把“吝啬”做到了机智,在函数对外访问权限设计中,连`public` 这样的关键词都不提供,直接使用首字母大小写来区分。 一开始我设想所有 `private` 访问权限函数全部使用 `_` 开头。看了一下golang中源码的一些实现方式,并没有这种习惯。索性就不采用这种方式。但很多时候这种规则容易忘记,尤其是我一开始直接使用 Sublime 编写代码时候,由于安装任何插件,没有代码提示,经常大小写搞混。 对于函数调用的问题还好,毕竟编译时候会提示你调用的函数不存在。但将 `struct` 转为字符串 和借助 `mgo` 查询数据时,会得到空的结果,极其令人头疼。与此同时,`struct` 作为数据库查询结果返回的时候,字段名称对应的首字母也要大写,和数据库中字段大小写不一致,这也是个不大不小的问题。 ### 内存 老生常谈的问题又来了,这20天对于golang的接触与使用,并没有太多关注内存的控制,顶多是对变量的开辟小心处理而已,但我相信依然存在不少内存方面的隐患,待仔细研究后再来总结分享。 ### 总结 总体来说,我对golang的使用体验还算满意,用起来像C。开发思路上没遇到大的问题,后续慢慢深入。 enjoy!