前言

GO语言的目的

  1. 更少的代码,更短的编译时间(与传统开发的C/C++相比)
  2. 创建运行更快的程序,高性能与安全性(与动态语言相比)
  3. 能够很好地在多核计算机上工作
  4. 能够做到在性能上和开发速度上基本不差于任何一门其他语言

GO语言提倡通过接口来针对面向对象编程,通过 goroutine 和 channel 来支持并发和并行编程。

学习GO语言

第1章:Go 语言的起源,发展与普及

在 Go 语言出现之前,开发者们总是面临非常艰难的抉择,究竟是使用执行速度快但是编译速度并不理想的语言(如:C++),还是使用编译速度较快但执行效率不佳的语言(如:.NET、Java),或者说开发难度较低但执行速度一般的动态语言呢?显然,Go 语言在这 3 个条件之间做到了最佳的平衡:快速编译,高效执行,易于开发。

设计者通过 goroutine 这种轻量级线程的概念来实现这个目标,然后通过 channel 来实现各个 goroutine 之间的通信。他们实现了分段栈增长和goroutine 在线程基础上多路复用技术的自动化。

依赖管理是现今软件开发的一个重要组成部分,但是 C 语言中“头文件”的概念却导致越来越多因为依赖关系而使得构建一个大型的项目需要长达几个小时的时间。人们越来越需要一门具有严格的、简洁的依赖关系分析系统从而能够快速编译的编程语言。这正是 Go 语言采用包模型的根本原因,这个模型通过严格的依赖关系检查机制来加快程序构建的速度,提供了非常好的可量测性。

尽管 Go 语言像其它静态语言一样执行本地代码,但它依旧运行在某种意义上的虚拟机,以此来实现高效快速的垃圾回收(使用了一个简单的标记-清除算法)。

Go语言通过减少关键字的数量(25 个)来简化编码过程中的混乱和复杂度。干净、整齐和简洁的语法也能够提高程序的编译速度,因为这些关键字在编译过程中少到甚至不需要符号表来协助解析

值得注意的是,因为垃圾回收和自动内存分配的原因,Go 语言不适合用来开发对实时性要求很高的软件。

Go 语言通过另一种途径实现面向对象设计来放弃类和类型的继承。它不支持动态加载代码,不支持动态链接库,不支持静态变量等。

第2章:安装与运行环境

目前有2个版本的编译器:Go 原生编译器 gc 和非原生编译器 gccgo

Go 语言本身是由 C 语言开发的,而不是 Go 语言

Linux安装过程:

vim ~/.bashrc

export GOROOT=/usr/local/go 							//前面GO的安装解压路径
export GOPATH=$HOME/Applications/Go 					//GO的工作路径,以后存放代码的地方
export PATH=$PATH:$GOPATH:/usr/local/go/bin				//为了确保相关文件在文件系统的任何地方都能被调用

source ~/.bashrcvim ~/.bashrc							//激活生效
go version
go env
package main

import "fmt"

func main() {
	fmt.Printf("hello world\n")
cd ~/Application/GO/src/hello     //这个目录好像需要自己创建的
go build hello.go
./hello

开发环境要求等

go fmt ( gofmt )
go doc

Go 语言与 C 语言的性能差距大概在 10%~20% 之间,Go 程序比 Java 或 Scala 应用程序要快上 2 倍,并比这两门语言使用少占用 70% 的内存。

GO可以调用C和C++代码

语言的核心结构与技术

go文件的命名以小写字母命名,多个单词用_连接。
对于可导出的对象,采用Pascal 命名法(第一个字母也是大写)
否则就遵循骆驼命名法,即第一个单词的首字母小写,其余单词的首字母大写。

基本结构和基本数据类型

你必须在源文件中非注释的第一行指明这个文件属于哪个包

如果你打算编译包名不是为 main 的源文件,如 pack1 ,编译后产生的对象文件将会是 pack1.a 而不是可执行程序。

在导入一个外部包后,能够且只能够访问该包中导出的对象(以大写字母开头,类似public)

如果你导入了一个包却没有使用它,则会在构建程序时引发错误,如 imported and not used: os ,这正是遵循了 Go 的格言:“没有不必要的代码!“。

函数定义规范:

func functionName(parameter_list) (return_value_list) {
…
}

parameter_list 的形式为 (param1 type1, param2 type2, …)
return_value_list 的形式为 (ret1 type1, ret2 type2, …)
类型

Go 语言中不存在类型继承,所有的内存在 Go 中都是经过初始化的(会初始化为默认值)

GO命名规范:返回某个对象的函数或方法的名称一般都是使用名词,没有 Get… 之类的字符,如果是用于修改某个对象,则使用 SetName 。有必须要的话可以使用大小写混合的方式,如 MixedCaps 或 mixedCaps,而不是使用下划线来分割多个名称。

//定义类型别名
type IZ int
type (
	IZ int
	FZ float64
	STR string
	)

//类型转换
var a IZ = 5
c := int(a)
d := IZ(c)
常量

因为在编译期间自定义函数均属于未知,因此无法用于常量的赋值,但内置函数可以使用,如:len()。

const beef, two, c = “meat”, 2, “veg”
const Monday, Tuesday, Wednesday, Thursday, Friday, Saturday = 1, 2, 3, 4, 5, 6
const (
Monday, Tuesday, Wednesday = 1, 2, 3
Thursday, Friday, Saturday = 4, 5, 6
)
//枚举
const (
Unknown = 0
Female = 1
Male = 2
)
变量
//这种因式分解关键字的写法一般用于声明全局变量
var (
a int
b bool
str string
)

Go 编译器的智商已经高到可以根据变量的值来自动推断其类型,Go 是在编译时就已经完成推断过程。变量的类型也可以在运行时实现自动推断

var (
HOME = os.Getenv("HOME")
USER = os.Getenv("USER")
GOROOT = os.Getenv("GOROOT")
)
package main
import (
"fmt"
"os"
) f
unc main() {
var goos string = os.Getenv("GOOS")
fmt.Printf("The operating system is: %s\n", goos)
path := os.Getenv("PATH")						//在函数体内声明局部变量时,应该使用简明语法
fmt.Printf("Path is %s\n", path)
}

所有像 int、float、bool 和 string 这些基本类型都属于值类型,另外,像数组(第 7 章)和结构(第 10 章)这些复合类型也是值类型。

在 Go 语言中,指针(第 4.9 节)属于引用类型,其它的引用类型还包括 slices(第 7 章),maps(第 8章)和 channel(第 13 章)。被引用的变量会存储在堆中,以便进行垃圾回收,且比栈拥有更大的内存空间。

打印的方法

  1. Printf:%s 代表字符串标识符、 %v 代表使用类型的默认输出格式的标识符,%t 来表示你要输出的值为布尔型
  2. fmt.Sprintf :与 Printf 的作用是完全相同的,不过前者将格式化后的字符串以返回值的形式返回给调用者,因此你可以在程序中使用包含变量的字符串
  3. 函数 fmt.Print 和 fmt.Println 会自动使用格式化标识符 %v 对字符串进行格式化,两者都会在每个参数之间自动增加空格,而后者还会在字符串的最后加上一个换行符

全局变量是允许声明但不使用,局部变量不允许

var a, b, c int
a, b, c = 5, 7, "abc" 			//已经声明过了
a, b, c := 5, 7, "abc"

a, b = b, a  //交换两个变量的值
4.5 基本类型和运算符

Go 不存在像 C 和 Java 那样的运算符重载,表达式的解析顺序是从左至右。

对于布尔值的好的命名能够很好地提升代码的可读性,例如以 is 或者 Is 开头的 isSorted 、isFinished 、 isVisivle ,使用这样的命名能够在阅读代码的获得阅读正常语句一样的良好体验

Go 语言中没有 float 类型。有float32,float64(这些是与架构无关的)

package main
func main() {
var a int
var b int32
a = 15
b = a + a // 编译错误
b = b + 5 // 因为 5 是常量,所以可以通过编译
}

对于整数和浮点数,你可以使用一元运算符 ++ (递增)和 – (递减),但只能用于后缀

同时,带有 ++ 和 – 的只能作为语句,而非表达式,因此 n = i++ 这种写法是无效的,其它像f(i++) 或者 a[i]=b[i++] 这些可以用于 C、C++ 和 Java 中的写法在 Go 中也是不允许的。

字符串的内容(纯字节)可以通过标准索引法来获取,在中括号 [] 内写入索引,索引从 0 开始计数

获取字符串中某个字节的地址的行为是非法的,例如: &str[i] 。

4.7 strings 和 strconv 包
4.8 时间和日期
4.9 指针

Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如: pointer+2 ,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和VB.NET 中的引用。