Go语言学习文档(一)

背景:
“Go是一个开源的编程语言,它很容易用于构建简单、可靠和高效的软件。”这是Go语言官方网站对自身的表述。
Go语言由来自Google公司的Robert Griesemer,Rob Pike和Ken Thompso于 2007年9月开始设计和实现,于2009年的11月对外正式发布,旨在具有表达力,高效的编译和执行效率,有效地编写高效和健壮的程序。
在这里插入图片描述

特点:
1、Go语言中具有和并发编程相关的特性,对数据抽象和面向对象编程的灵活支持,同时还集成了自动垃圾收集技术用于更好地管理内存。

2、Go语言尤其适合编写网络服务相关基础设施,同时也适合开发一些工具软件和系统软件。 但是Go语言是一个通用的编程语言,它也可以应用在图形图像驱动编程、移动应用程序开发和机器学习等诸多领域。同时由Go编写的程序通常比脚本语言运行的更快也更安全,而且很少会发生意外的类型错误。
3、Go语言鼓励当代计算机系统设计的原则,特别是局部的重要性。它的内置数据类型和大多数的准库数据结构都经过精心设计而避免显式的初始化或隐式的构造函数,因为很少的内存分配和内存初始化代码被隐藏在库代码中了。

4、由于现代计算机是一个并行的机器,Go语言提供了基于CSP的并发特性支持。Go语言的动态栈使得轻量级线程goroutine的初始栈可以很小,因此创建一个goroutine的代价很小,创建百万级的goroutine完全是可行的。

5、Go语言的标准库,提供了十分清晰的构建模块和公共接口,包含I/O操作、文本处理、图像、密码学、网络和分布式应用程序等,并支持许多标准化的文件格式和编解码协议。

入门知识:
如果从一段最简单的代码出发分析

package main

import "fmt"

func main() {
    fmt.Println("Hello")
}

具体的用法与格式不在学习文档中赘述,本学习文档记录学习过程中让本人感到特殊、重要的知识点等。

我们考虑
1、main包
它定义了一个独立可执行的程序,而不是一个库。在main里的main函数 也很特殊,它是整个程序执行时的入口,当然它也能够调用很多函数完成工作。

2、与python这类语言不同,Go语言在代码格式上非常严格,例如函数声明时的括号就必须与函数在同一行,如果你调用了一个库而不使用也不被允许。

3、入门学习时特别的语句,这两种方式伴随着本人入门时的几乎每一个程序:
1)唯一的循环语句for

for initialization; condition; post {
// zero or more statements
}

其中,initialization语句是可选的,在循环开始前执行。initalization如果存在,必须是一条简单语句,即,短变量声明、自增语句、赋值语句或函数调用。condition是一个布尔表达式,其值在每次循环迭代开始时计算。如果为true则执行循环体语句。post语句在循环体执行结束后执行,之后再次对conditon求值。condition值为false时,循环结束。

2)在区间(range)上遍历
range的语法要求, 要处理元素, 必须处理索引,Go语言中解决方法是用空标识符,即_(下划线)。空标识符可用于任何语法需要变量名但程序逻辑不需要的时候。

4、指针
指针是可见的内存地址,&操作符可以返回一个变量的内存地址,并且*操作符可以获取指针指向的变量内容,但是在Go语言里没有指针运算。

程序结构
1、命名
一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。值得注意的是大写字母和小写字母是不同的

2、声明
四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明。
在包一级声明语句声明的名字可在整个包对应的每个源文件中访问,而不是仅仅在所在的源文件中访问,而局部声明则无法做到这样

3、变量
特殊的点:接口或引用类型(包括slice、map、chan和函数)变量对应的零值是nil。同时由于Go语言具有零值初始化机制,因此我们不需要担心有变量未初始化的问题。
初始化的时序为:在包级别声明的变量会在main入口函数执行前完成初始化,局部变量将在声明语句被执行到的时候完成初始化。

4、赋值
基本与其他语言都保持一致
特殊点:
A[i] = A[i] * x
可以简化为:
A[i] *=x
这样可以省去一些对表达式的反复计算

5、作用域
声明语句对应的词法域决定了作用域范围的大小。对于内置的类型、函数和常量,比如int、等是在全局作用域的,因此可以在整个程序中直接使用。任何在函数外部声明的名字可以在同一个包的任何源文件中访问的。对于导入的包,只能在当前文件中访问。

数据类型
几大数据类型:
整型、浮点数、复数、布尔型、字符串、常量

运算符优先级顺序:
在这里插入图片描述
位运算符
在这里插入图片描述
数组与切片
1、数组
是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,因此在Go语言中很少直接使用数组。

2、切片
和数组对应的类型是Slice(切片),它是可以增长和收缩动态序列。Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。一个slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象。一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址
需要注意的是slice之间不能比较,我们可以使用标准库提供的bytes.Equal函数来判断两个字节型slice是否相等([]byte),但是其他类型的slice,我们必须展开每个元素进行比较,slice唯一合法的比较操作是和nil比较。

MAP哈希表
哈希表是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。一个map就是一个哈希表的引用,map中所有的key都有相同的类型,所有的value也有着相同的类型,赋值语法也可以用在map上,但我们不能对map的元素进行取址操作,可以通过前文提到的range来实现遍历,但这样的遍历是随机的根据哈希表的特性。

*****在Go语言的数据类型中还具有结构体、JSON、文本、HTML模板这样的类型,在作者书写这份文档时,尚且没有接触,在后续的Go语言学习文档中期待补充。

接口
1、定义:
接口类型是一种抽象的类型,它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合;它们只会展示出它们自己的方法。
例如我们频繁使用的fmt.Printf和fmt.Sprintf,实际上,这两个函数都使用了另一个函数fmt.Fprintf来进行封装。在Printf函数中的第一个参数就不是一个文件类型,它是io.Writer类型,这是一个接口类,fmt.Fprintf函数没有对具体操作的值做任何假设而是仅仅通过io.Writer接口的约定来保证行为
因此我们可以得到接口的类型:io.Writer类型是用的最广泛的接口之一,它提供了所有的类型写入bytes的抽象,包括文件类型,内存缓冲区,网络链接,HTTP客户端,压缩工具,哈希等等,同时我们可以通过已有的接口来定义新的接口类型。

2、接口指定的规则:
表达一个类型属于某个接口只要这个类型实现这个接口

3、接口值
由两个部分组成,一个具体的类型和那个类型的值。它们被称为接口的动态类型和动态值,接口值是可比较的,所以它们可以用在map的键或者作为switch语句的操作数。
然而,如果两个接口值的动态类型相同,但是这个动态类型是不可比较的(比如切片)

4、flag.Value接口: link.

5、sort.Interface接口: link.

6、http.Handler接口: link.

7、error接口: link.

8、类型断言
是一个使用在接口值上的操作。语法上它看起来像x.(T)被称为断言类型,这里x表示一个接口的类型和T表示一个类型。一个类型断言检查它操作对象的动态类型是否和断言的类型匹配
两种情况:
1)如果断言的类型T是一个具体类型,然后类型断言检查x的动态类型是否和T相同。如果检查成功了,类型断言的结果是x的动态值。换句话说,如果检查失败,接下来这个操作会抛出panic。

2)如果相反断言的类型T是一个接口类型,然后类型断言检查是否x的动态类型满足T。如果这个检查成功了,动态值没有获取到;这个结果仍然是一个有相同类型和值部分的接口值,但是结果有类型T。因此对一个接口类型的类型断言改变了类型的表述方式,改变了可以获取的方法集合,但是它保护了接口值内部的动态类型和值的部分。

他可用于识别错误类型和查询接口

Goroutines和Channels
1、goroutine
每一个并发的执行单元叫作一个goroutine,我们可以可以简单地把goroutine类比作一个线程,当然他们也存在一些区别。
当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine。新的goroutine会用go语句来创建。除了从主函数退出或者直接终止程序之外,没有其它的编程方法能够让一个goroutine来打断另一个的执行。

2、channels
Channels是Go语言程序之间的通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息,channel的类型是根据可发送数据的类型改变,例如发送int类型数据的channel写为:chan int,使用make函数创建,零值位nil,可以用close命令1关闭channel
在这里插入图片描述

本学习文档至此只阐述、归纳了Go语言学习框架中相当部分的主体内容,还有许多内容等待进一步记录、学习,例如在Goroutines和Channels部分还可以讨论进一步基于共享变量的并发,以及Go语言运行时更新检查变量的机制:反射也等待拓展,这些部分期待在未来完成。

参考:
1、link.
2、link.
3、link.


版权声明:本文为weixin_43550014原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。