很久没发博客了,这个本来是记在有道云笔记上面的,分享一下吧。

力扣在坚持每天打卡,然后看一些书/教程/文档和网课。偶尔打两把游戏。。感觉时间不够用呐。。

learning is keeping

读取配置文件

conf在项目根目录下,关于go的路径读取还有很多问题,比如go run,和go build之后运行二进制文件的路径是不一样的。

1
data, err := ioutil.ReadFile("conf/app.yaml")

读取yaml文件

这里map读出来的都是interface{}类型,所以我通过断言转了一下,不知道有没有问题。

1
2
3
4
5
6
7
8
9
10
11
data, err := ioutil.ReadFile("conf/app.yaml")
if err != nil {
log.Fatalf("read config file app.yaml err: %v", err)
}
m := make(map[interface{}]interface{})
err = yaml.Unmarshal(data, m)
if err != nil {
log.Fatalf("yaml.Unmarshal read error: %v ", err)
}
// 使用断言,将interface{}转为string
RunMode = m["RUN_MODE"].(string)

goland使用filewatcher,goimports下载失败

  1. 设置代理,打开设置->搜索proxy->找到Http Proxy->设置Manual proxy configuration
  2. 检查连接 check connection (golang.org)
  3. 在goland的控制台运行,go get golang.org/x/tools/cmd/goimports
  4. 再次进入filewatcher界面,添加goimports

go get命令的参数

  • -d 只下载不安装
  • -f 只有在你包含了 -u 参数的时候才有效,不让 -u 去验证 import 中的每一个都已经获取了,这对于本地 fork 的包特别有用
  • -fix 在获取源码之后先运行 fix,然后再去做其他的事情
  • -t 同时也下载需要为运行测试所需要的包
  • -u 强制使用网络去更新包和它的依赖包
  • -v 显示执行的命令

goland无法和vscode一样看提交历史和变更文件

和vscode一样看每行代码的提交信息

下载插件GitToolBox即可,默认配置就支持,更多配置功能自己研究。

和vscode一样看当前修改文件之类的。

打开设置->搜索commit,把use non-modal commit interface勾上->点击应用。你会看到左侧边栏出来了一个commit模块,点开就行。

golang提前声明返回值

代码中,(count int)在函数末端显示声明的返回值变量,可以在函数中直接使用,并且不用显示返回,直接写return就可以了

1
2
3
4
func GetTagTotal(maps interface{}) (count int) {
db.Model(&Tag{}).Where(maps).Count(&count)
return
}

gorm连接数据库报错

unknown driver "mysql" (forgotten import?),字面意思就是没有引入mysql包,按理说应该会自动引入的,但如果你没有直接使用这个包的方法,gorm包不会帮你引入这个包。坑啊
如果直接这样:

1
2
3
4
5
import{
...
"github.com/go-sql-driver/mysql"
...
}

你使用了filewatcher里的go imports功能的话,一保存就会消失,所以要这样:

1
2
3
4
5
import{
...
_ "github.com/go-sql-driver/mysql"
...
}

time.Duration

一定要记住time.Duration的默认单位是纳秒。
我被这个坑了一两个小时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
router := routers.InitRouter()
s := http.Server{
Addr: fmt.Sprintf(":%d", setting.HttpPort),
Handler: router,
ReadTimeout: setting.ReadTimeOut,
WriteTimeout: setting.WriteTimeOut,
MaxHeaderBytes: 1 << 20,
}
err := s.ListenAndServe()
if err != nil {
log.Fatalf("server start err: %v", err)
}
}

上面代码就是正常启动一个服务,我启动后一个调不通。
然后排查了很久发现是ReadTimeoutWriteTimeout的锅,我配置文件本意是配几千毫秒,但是timeDuration类型默认是纳秒,所以这个服务器的超时时间就是几千纳秒。。。

golang []int转string

js可以通过[1,2].join(",")转换为"1,2"

但是golangstrings.Join()只能把字符串数组转为字符串。。

所以我去stackoverflow上面找了一个转换的方法:

1
2
3
4
5
6
func arrayToString(a []int, delim string) string {
return strings.Trim(strings.Replace(fmt.Sprint(a), " ", delim, -1), "[]")
//return strings.Trim(strings.Join(strings.Split(fmt.Sprint(a), " "), delim), "[]")
//return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(a)), delim), "[]")
}

gin框架编写全局错误处理中间件

教程里都是微信小程序那种接口返回方式,无论成功失败都返回200,然后用自己定义的一个json格式里的code区分状态。

但我还是喜欢Restful Api的方式,所以我就去研究了一下怎么全局捕捉异常,就和Node.js一样。

  1. 先去掉gin.Recover这个中间件
  2. 加上这样一个中间件,可能和百度搜到的gin的中间件写法不太一样,没有返回一个
    gin.HandleFunc,我猜这和中间件的执行顺序有关吧,没有细看,抽时间研究一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func Recover(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
if data, ok := r.(map[interface{}]interface{}); ok {
code := data["code"].(int)
msg := data["msg"].(string)
log.Printf("panic: %v\n", r)
//封装通用json返回
c.JSON(code, gin.H{
"msg": msg,
})
} else {
log.Printf("panic: %v\n", r)
// 走到这里说明是未知错误,打印一下堆栈信息
debug.PrintStack()
c.JSON(http.StatusInternalServerError, gin.H{
"msg": "服务器发生未知错误,请通知管理员!",
})
}
}
}()
//加载完 defer recover,继续后续接口调用
c.Next()
}
  1. 使用panic(map[interface{}]interface{})这样抛出错误,就可以被捕获到,当然数据结构你可以自己定义。
  2. 然后里面有几个知识点,r是一个map[interface{}]interface{},必须要使用断言才能从中读取值,参见https://stackoverflow.com/questions/25214036/getting-invalid-operation-mymaptitle-type-interface-does-not-support-in
  3. 然后code := data["code"].(int) msg := data["msg"].(string) 这种写法和前面读取yaml文件时说的一样,interface{}的类型要用断言转一下。参见https://stackoverflow.com/questions/18041334/convert-interface-to-int
  4. ps: 反正你用空接口的时候,取值就尝试用断言去转一下类型,不然肯定取不到的。