
本篇文章开始,正式进入GO的语言部分学习。为了更有计划性,决定先整体梳理下接下来要学习的内容,主要是为了理清我的思路。如有错误,帮忙指正。
概述性介绍
我们知道,计算机只能执行机器指令(即0和1),但机器指令对人类是相当地不友好,为了提高生产力,便产生了很多高级语言。无论什么语言都离不开两点,即指令和数据。
程序负责处理信息,接收输入,处理和输出。输入信息可能来自鼠标、键盘、磁盘等设备,输出通过屏幕、打印机、音频设备等实现。这些输入输出在程序中都需要相应的表示,这些就是数据。
数据需要处理,这个过程可能非常复杂。要完成这个工作,编程语言需支持各种功能,从基本的运算比较操作到流程控制、程序组织、包的管理、反射等,为了性能的考虑,通常还包括并发编程。

从这些角度出发,在综合了大量的GO语言资源后,整理出了接下来将要学习涉及的内容。总共分了十个部分的内容。本文只作简单介绍,以后再慢慢拆解。
命名
命名的规范应该是一门语言最基础的部分了。GO语言中的常量、变量、函数、类型、包等一系列符号的命名都要满足一个基本的规范,即下划线或字母(包括Unicode字母)开头 + 任意数量的字母(包括Unicode字母)、下划线或数字。
关于命名,我认为有三个需要特别注意的点。
GO的命名逻辑上是没有长度限制的,但一般建议命名最好是短小简洁。
GO的命名可以是Unicode字母,所以中文的命名也是可行的,比如变量定义 var 我的名字 = "poloxue",毫无问题。
GO中的命名如果是中文,一律按小写对待,为什么要注意这点,因为GO中包的可见性是由命名的大小写决定的。
数据
关于数据,在GO中的表示,可以从两个不同的角度来看。一个是从数据类型角度,每个数据都有一个指定的类型。另一个不知该怎么描述,一般都把数据以字面量、常量、变量三种形式展现,姑且就认为是从展现的角度吧。
数据类型
GO中的数据类型可以分为基本类型和复合类型。基础类型包括如布尔型、整型、浮点型、复数类型以及字符串类型。复合类型包括数组、切片、映射、结构体。
除此之外,还有一些特殊类型,比如channel、function、指针、interface等。它们都有着特定用途,待到具体专题再介绍。
在GO中,我们可以定义新的类型,声明别名或自定义。而这些都可以通过type关键词完成。
展现形式
从展现角度来看,数据可以分为字面量、常量和变量三种形式。
字面量是源码中一种固定值的表示方法,比如 "poloxue",字面量在赋值表达式中,通常位于右边。基本每种数据类型都有其字面量的表示方式。不同数据类型的字面量表示形式不同。后面会把字面量和数据类型放在一起介绍。
常量即恒常的量,在程序运行期间不可改变。常量通常可提高代码可读性。一些常识性、状态标志位之类的值常定义为常量,比如圆周率、文件标志位O_RDONLY等。GO中的常量定义通过const实现,为了提高开发效率,还提供了便于常量定义的itoa。
变量,与常量对比,它在程序的运行期间是可以被改变的。变量,在程序执行期间,可帮助存储程序处理的中间数据以及最终结果。GO中的常量定义语法多样,除了静态语言变量定义的标准方法,还支持类似动态语言变量定义方式,根据值推导变量类型。
表达式
表达式是程序的一行行组成单位,一般都是有数据和运算符组成。
前面,数据已经说过了。运算符也是不可少。编程语言一般都有算术运算符、位运算符、赋值运算符,比较运算符,地址运算符和管道相关操作符。不同的运算符有不同的优先级,但只要记住个大概就行了,学了那么多年编程很多我也没高清楚,搞不懂的时候,括号用起来就好了。
由算法运算符和数据组成的就是算法表达式,以此类推,还有位运算表达式、赋值表达式、比较表达式等等。除了这些,还有如管道操作的表达式、指针获取值表达式等。
挺乱的,有点晕。
流程控制
谈到流程控制,就要讲结构化编程的三种结构:循序、分支和循环。默认便是就是顺序结构。这里主要谈分支、循环。
GO中的分支控制语句包括 if else、switch case、select case。if else 和其他语言差不多,条件判断决定执行流程。switch case 根据运算结果选择执行分支。selelct case主要用来并发场景下的channel,使用了通信的多路复用。
GO中的循环语句只提供了 for ,从这一点也能感受到 for 的功能必然很轻大。首先,它肯定可以实现传统的 for 初始化;条件表达式;运算表达式 的循环,它也能实现其他语言中 while 循环的效果。而且这个 for 对并发通信支持良好,还能接收那些发送给 channel 的数据,。
除了这两者,GO中还提供了一种新的流程控制,通过defer关键词实现,defer语句的直线井在函数返回时触发。我认为,最直接的好处就是简化了函数的资源释放清理、异常处理等工作。
函数
函数代表的是一段代码片段,通过函数,我们能实现代码逻辑的重用。函数定义需要明确三部分内容:函数名、输入与输出。
GO中的函数定义通过 func 关键词实现,支持匿名函数。输入参数除了定长参数,还支持可变参数,通过 slice 数据类型和 ... 组合传递,接收的是 slice 类型参数。输出参数,不同于其他的一些静态语言,支持多返回值。
面向对象
GO中的面向对象非常灵活,与传统的面向对象相比,GO没有如继承、构造函数等面向对象中常见的复杂概念。
GO的面向对象强调组合,基于接口编程,类似鸭子模型(duck typing)。在介绍GO的书中,可能都找不到面向对象这个词,而通过组合,我们可以非常简单地给任意类型增加动作方法。基于接口,我们可以实现面向对象的多态。
包
多数语言都提供了源码包管理支持,C++和 PHP 的名字空间(或命名空间)、Java 和 python的包、NodeJS 的模块化。GO 的源码通过包组织,是各种数据、函数、方法的集合。
包的管理涉及两部分,包的创建和导入。包通过 package 定义声明,包有main包和非main包两种。包的导入通过 import 语句,和其他语言一样,GO中也支持别名、匿名导入。
错误处理
GO的错误处理与其他语言不同,主要分两种情况来看待,分别常规错误、严重的异常。
对于常规的错误,GO的建议是以函数返回 error 类型信息来表明程序的是否有错误。所以阅读GO的代码时,时常可以看到 if err != nil 代码片段。error 可以系统内置的,我们也可以自定义新的 error 类型,只要实现 error 接口的要求实现的方法即可。
对于严重异常,主要是通过 panic 和 recover 来处理。它们有点类似其他语言的异常处理,常会结合 defer 实现在函数出口检测运行中是否有 panic 发生。
并发模型
一般谈到并发,基本都是进程或线程类的话题。GO与之不同,在GO中的并发是通过协程实现,它的运行单元称为goroutine(其它一些语言中称为coroutine)。
一个新的协程需要以 go 表达式来运行,也会涉及数据竞争的问题。goroutine 间的通信可以通过传统的并发机制实现,也可以使用go中的一个新的技术 channel 管道技术。可以利用 select 实现goroutine的多路复用。
反射
反射为计算机编程语言提供了自省的能力。它可以实现在动态语言(解释型语言)中非常容易实现的一些功能。
要掌握反射,就要了解一个数据是如何表示的,主要可以分为类型和值,即 Type 和 Value。关于Type,要了解GO语言的类型系统,除了前面介绍的基本数据类型和复合数据类型,GO还有一些特殊类型,比如 interface、channel等。对于值,要清楚不同的类型值内部结构是存在差异的。
总结
本文梳理了GO语言中各类知识点,主要为了指导我接下来的笔记。如果大家发现一些地方存在错误,请帮忙指正。在后面的学习中,我也会重新检查这篇文章。