抓了只水蓝色的地鼠玩玩

抓了只水蓝色的地鼠玩玩

编程那点事 随便写写 Go 2240 字 / 4 分钟

第一次听说 Golang,还是在上学期刚加入杭电助手的时候。当时跟大家还不熟,我在群里还挺腼腆的。当时部长开了个让我记忆犹新的玩笑:

我们或许可以期待一下 Google 推出 ogle 语言。

真香

刚开始我其实一直对 Golang 无感,和部长半开玩笑半认真地吹 PHP,觉得 Go 能做的,PHP 其实也能做到。只是具体的实现方式不同罢了。 但是前阵子在折腾 PHP 自动部署时,有过写一个类似 Drone 的图形化部署界面的想法。这时,我才隐隐意识到,PHP 这种不需要编译的语言的“别扭”之处。 PHP 主要用于 Web 应用的开发,虽然她也有 CLI 模式,但毕竟不是很常用,也就 Composer 那边会用用。很多时候,为了安全考虑,我们都会选择禁用掉诸如eval system exec等函数。然而有些操作比如想使用 git 时,又不得不使用这些去执行git pull git clone,所以就很矛盾了。

之后,我了解到 Docker 居然是使用 Golang 编写的,以及知乎等一系列大厂都使用 Golang 重构后;我感觉这个语言可能确实是有点厉害啊。

初遇

于是,我逐渐开始接触这个语言。我才发现他真的有毒。 一般的语言,什么都没学,直接上来还是能看懂一些的。而这个 Go 嘛…… 这个:=是什么?怎么函数的前面,后面都有括号传参,怎么函数名后面还有两个括号??? 真的是一脸懵逼啊。 上网找了个菜鸡教程看了下,在明白了一些。卧槽,这语言居然可以有多个返回值!!这语言的语法怎么和 C 那么像!!

昨天在协会写了一天的 Go。其实是摸了一天的鱼再加上晚上部长面授 SQL 数据库操作;今天我终于用 Go 写完了一个留言板的后端 API。 自己也从中摸索到了一些东西。感觉其实只要会了数据库的增删改查,就能够写不少东西了。那借着这个契机,我来聊聊我所理解的 Go 和 PHP 的不同。

水蓝色地鼠 VS 紫色大象

编译型 / 解释型

Go 是一门编译型语言,这使得他写出来的应用是打包成一个可执行的二进制文件执行。而 PHP 则就是.php文件,然后用 PHP 解释器运行。这使得 PHP 修改起来确实方便很多,直接以文本形式打开,改完保存。而 Go 则需要重新编译一次。同时,Go 也没有像 PHP__LINE__这种属性或者eval这种很有意思的东西。但 Go 一打包出来就是二进制文件,源码得到了保护,并且因为是一个整体,我想迁移起来应该也很舒服。

Web 服务器??

用 PHP 来搭建一个 Web 应用,你总需要装诸如 Nginx 或 Apache 这样的服务器软件,来处理 HTTP 请求,并把相应的请求转发给后面的 PHP 解释器。而 Go 就只是一个可执行文件,全部都包在里面了,直接作为守护进程运行在后台即可。这应该也是为什么 Drone 部署 Go 应用都直接就是打包成一个 Docker 镜像。

语法相关

我想 Go 比较有意思的,就是他的函数可以有多个返回值。这个我感觉真的不多见。不过写了一些 Go 之后,我也能大概理解他这么做的用意的。Go 中并没有throwtry catch语句来抛出或捕获异常,全部的异常处理都是在函数中以一个error的返回值来实现的。只需要判断一下返回的error变量是不是nil,就可以知道有没有异常了。 同时,Go 为了提高性能,节省不必要的内存开销,规定变量不允许仅定义而不使用。我想因此也就产生了:=申明并赋值这么一个奇怪的操作符。 并且 Go 真的是兼具了不同语言的特点啊,这使得他有点像一个“不三不四”的结合体——虽然是一个强类型的语言,但是还具有JavaScript或者说是Swiftvarfunc关键字。同时又是类型后置,需要在变量名后输入变量类型。这就导致一个函数的声明有时候会看起来十分奇怪:

func (s *Service) register (c *gin.Context)(int, interface{}){
	type registerForm struct{
		UserName 	string
		Password 	string
		Mail 	 	string
	}
	
	var token string
	...
}

这也就是为什么我一上来看 Go 就一脸懵逼的原因。

Gin,好喝!

好像部长和 Hammer 学长都推荐使用 Gin 这个 Go web 框架写后端 API。我便用这个,顺便参照着部长之前写的 CRUD 的 Demo,写的留言板后端。一顿写下来,确实说不出的畅快。畅快到让我感觉这东西封装了太多,而我刚开始入门就用这么简单的框架,不去深入了解 Go 的一些原生语法、实现会不会不太好。但真的是 Gin 写 API 一时爽,一直用 Gin 一直爽。 路由的声明很直接,HTTP 方法应有尽有,就不存在 PHP + Nginx 的 DELETE 方法的坑。 并且,直到用了 Gin,我才明白 Go 中那些让人感觉很烦的结构体的好处到底在哪了。 在 Go 中,比如我要获取一个 POST 过来的 JSON 数据。我需要先声明一个和发送过来的 JSON 数据一样的结构体。 比如,发送过来的 JSON 是:

{
	"UserName": "E99p1ant",
	"Password": "123456"
}

那我在 Go 中,就需要声明一个如下的结构体:

type userForm struct{
	UserName string
	Password string
}

因为 Go 是强类型语言,所以我们不得不在这里声明结构体中元素的类型。 之后我们需要用 Gin 里面的BindJSON()ShouldBindJSON()方法来将传入的 JSON 绑定到一个结构体的实例上:

input := new(userForm)
err := c.ShouldBindJSON(input)

然后他的妙处就体现了,我们只需要判断这个err是否是nil,就可以做到检查 JSON 的入参是否有问题!!(但是我这样写好像并不能判断传入的参数是否为空,我现在是自己再用if判断,看 Gin 的文档中,好像有别的方法可以解决。

同时,提前声明结构体,表明要传入的数据的值的做法,使得 Go 中的一个 SQL 构造器 GORM,可以在判断到数据表不存在时,根据结构体的数据类型建立数据表。(然而我并不喜欢 GORM,不太习惯他那种方式,还是用 Go 原生的数据库中的预编译查询舒服。(可能是因为习惯了 PHP 的 PDO 吧,嘻嘻

真是很舒服很享受的过程啊

像 Go 这种又是编译型,还经常被用来写 Web,同时又是打包成可执行二进制的,真的是很难得啊。之后就是在服务器上搭好 Drone,把 Go 的自动部署给解决了。顺便再随便用 Vue 撸一个留言板的前端,把留言板放上去。我承认自己真香了,Go 真的是天下第一!!

但是,正妻还是 PHP,Golang 嘛……后宫之一咯~