N天学会Go语言

之前一直有了解 Go 语言,但没系统的学习,最近兴趣盎然生计所迫,得学一学了。整体来说 Go 语法很简洁,有其它语言基础的话学起来很快的。本文记录了一些学习笔记,加深理解。

基础语法

学语言,最重要的就是官方教程(https://go.dev/tour/list),建议不要一开始就跟着杂七杂八的教程学习。

变量

我们都知道 Go 语言是强类型的语言,所以定义变量的时候需要定义其类型,但像 C、Java,都是把类型放在前面:

咋一看有些别扭,但这有讲究的,比如符合英语系自然语言习惯,还有写起来就很方便,更突出变量名而不是类型(而且类型可以省略),官方博客有更多的介绍:Go's Declaration Syntax。还有,Go 和 Python一样,不需要写分号。

也还有简写的方式,因为定义变量的时候其实类型是确定的,编译器很容易推导,可以不用写类型。

看到var i = 1是不是有 JS 和 Java lombok/JDK10 的感觉,这样就很亲切了。

Methods are functions

一个函数定义:func add(x int, y int) int {},参数类型,返回值类型一目了然,这里可以看出还是类型后置,这点其实后面 Python 3.5 加入类型提示(限制)也是这样:def add(x: int, y: int) -> int:。这里顺带提一下,Python、PHP 这些无类型声明的语言并不是真的无类型(动态类型,运行时检查),而且新版都增加了类型检查的语法,解决了重构等痛点问题。

方法和函数其实一样,只是接收方参数不一样。

不过 Go 的函数没有 Python 的那么强大,没有默认参数、关键字参数等,虽然说 Go 讲究简洁,但这些语法糖还是很有用的,典型场景就是 Python requests 库:https://docs.python-requests.org/en/latest/api/#requests.request

Defer

延迟调用,这个比较特殊,defer定义的操作会在方法 return 后执行,但比如传的参数就是定义时那样,官方例子修改下:

输出

这个有什么作用呢,其实类似 Java 中 try/catch 中的 finally,可以用于资源的清理(经典应用就是释放锁)。官方博客有介绍:Defer, Panic, and Recover

Pointers

Go 的指针语法上来看,比 C 简单些,没有特殊的指针变量,&就是取地址,*就是取值(或者定义指针类型),也没有指针运算(其实也可以)。说到指针,又会牵扯到一个话题,传值还是传引用,简单来说 Go 传的是值,但并不代表改动不影响原数据,因为 map、slice等,可以理解本身数据结构就是指针,这些类型修改会影响原有数据,表现和其它语言一致。还有一个就是性能问题,本能的觉得传引用(指针)性能更高(其实还会带来 GC 等问题),比如字符串。

输出为:

咋一看 s2, s3 都是一个新的内存地址,这不影响性能嘛。但再看看:

输出:

可以看出 Go 对字符串等有两个优化:

1. 定义变量 literals(字面量)一致时(s1 和 s2),会指向同一个地址。

2. 变量传值时(s3 := s1)复制的是 string 这个数据结构。

data 指针指向的内容没有复制。因为要存储这个新的结构体,所以 &s3 是这个结构体的内存地址,而 s1,s3 结构体中 data 指向的地址是一样的。

指针这块细节可能理解不是太准确,但意思是语言层面已经做了很多优化,正常使用即可,不要过度优化到处使用指针。 Continue Reading...