原文链接:[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!