<Go>1 Go 基础知识

本文最后更新于:2023年6月27日 上午

1 Go 基础知识

Google 为什么要创造 Go 语言:

  • 计算机硬件技术更新频繁,性能提高很快。但目前主流编程语言发展明显落后于硬件,不能合理利用多核多 CPU 的优势来提示软件系统性能
  • 软件系统复杂度越来越高,维护成本也越来越高。目前缺乏一个足够简洁高效的编程语言
  • c / c++ 程序运行速度虽然很快,但编译速度很慢。同时存在内存泄漏等一系列困扰。

Golang 官网

Golang 标准库 API 文档,或者也可以试试 这个网址

#Go 语言发展史:

  • 2007 年,Google 开始设计一门全新的语言,这是 Go 语言的原型
  • 2009 年 11 月 10 日,Google 将 Go 语言以开放源代码的方式向全球发布
  • 2015 年 8 月 19 日,Go 1.5 版发布。本次更新中 “移除了最后残余的 c 代码”
  • 2017 年 2 月 17 日,Go 语言 Go 1.8 版发布
  • 2017 年 8 月 24 日,Go 语言 Go 1.9 版发布
  • 2018 年 2 月 16 日,Go 语言 Go 1.10 版发布
  • 目前的最新版本是 Go 1.18

#Go 语言的特点:

Go 语言既能到达静态编译语言的安全和性能,又达到了动态语言开发维护的高效率。

  • Go 从 c 语言中继承了很多概念,包括表达式语法,控制结构。基础数据模型。调用参数传值,指针等。也保留了和 c 语言一样的编译执行方式和弱化的指针。
  • 引入包的概念,用于组织程序结构。Go 语言的每一个文件都要归属于一个包,而不能单独存在。
  • 垃圾回收机制,内存自动回收,不需要开发人员管理
  • 天然并发:
    • 从语言层面支持并发,实现简单。
    • goroutine,轻量级线程。可以实现大并发处理,高效利用多核
    • 基于 CPS 并发模型(Communicating Sequential Processes)实现
  • 吸收了管道通信机制,形成 Go 语言特有的管道 channel。通过管道可以实现不同的 goroutine 之间的相互通信
  • 函数可以返回多个值
  • 新的创新:如切片 slice、延时执行 defer 等

1.1 Go 执行流程

通过编译器,将 Go 源文件编译成机器能识别的二进制码文件的过程称为 编译

在文件目录下使用 go build 指令以编译文件。此时,可以指定生成的文件名

  • 先编译,再执行([ ] 内的内容能省略)

    ******>go build [-o 可执行文件名] 源文件名
    ******>可执行文件名
    graph LR
    A(.go 文件)--go build 编译-->B(可执行文件)--运行-->C(结果)
  • 直接对源码执行 go run 命令

    ******>go run 源文件名
    graph LR
    A(.go 文件)--go run 编译运行一步-->C(结果)

两种执行方式的区别:

  1. 编译可执行文件后,将该文件放到没有 Go 开发环境的设备上仍能运行

    使用 go run 运行文件则需要 Go 开发环境

  2. 编译时,编译器会将程序运行依赖的库文件包含在可执行文件中。因此,可执行文件占用空间较大。

1.2 Go 开发注意事项

  1. Go 源文件以 .go 为扩展名

  2. Go 应用程序的执行入口是 main() 方法

  3. Go 语言严格区分大小写

  4. Go 方法由一条条语句构成,每个语句后可以不加分号(Go 语言会在每行后自动添加)

  5. Go 编译器是逐行翻译的。因此,不能将多条语句写在同一行

  6. Go 语言定义的变量或 import 的包如果没有用到,就不能编译通过

  7. 可以使用 gofmt 指令来对代码进行整理

    ******>gofmt -w 源文件名

1.3 注释

用于注解说明解释程序的文字就是注释。注释提高了代码阅读性。被注释的文字不会被 Go 编译器执行。

Go 语言中注释有两种形式:单行注释和多行注释

// 单行注释
/* 多行
	注释 */

注释不能嵌套注释。Go 官方推荐使用单行注释来注释整个方法和语句

1.4 变量

变量是程序的基本组成单位,相当于内存中一个数据存储空间的表示。该存储区域有自己的名称(变量名)和类型(数据类型)

Go 语言中变量的声明有以下形式:

  • 指定变量类型。声明后不赋值的场合,使用默认值

    var i int				// var 变量名 数据类型
    i = 100					// 赋值
  • 根据赋值自行判断数据类型(类型推导)

    var i = 10				// var 变量名 = 值
  • 省略 var,使用 :=

    i := 20					// 变量名 := 值
  • 一次性声明多个变量

    v1, v2, v3 := 100, "Go", 3.2

在函数体外声明的变量称为全局变量

var n1 = 100				// 全局变量
var (
	n2 = 200				// 另一种全局变量的声明方式
    n3 = 300
)

func main() {
    ...
}

使用细节:

  • 不能使用 := 方式声明全局变量

    因为 := 等同于一个 变量声明 + 赋值语句。在函数体外可以声明变量,但不能执行语句(也就不能执行赋值语句)

  • 全局变量即使没有使用过,也能编译通过

1.4.1 常量

常量是变量的一种。使用 const 而非 var 修饰的变量称为常量。

const ci int = 100
const c2 = 1000			// 也能直接省略那个类型名
const c3 = ci - 5

在函数体外声明的常量称为全局常量

const (
	i = 100
    ui uint64 = 9
)

使用细节:

  • 常量必须在声明时即赋值

  • 常量赋值后不能更改。

  • 常量只能修饰 bool、数值类型、string 类型。

  • 常量即使没有使用过,也能编译通过

  • 常量必须在编译阶段确定数值。可以使用表达式对常量赋值,但表达式中 不能含有任何变量

  • 可以使用 iota 对常量进行序号赋值

    const (
        o0      = 100					// 100
        o1, o11 = iota, iota			// 1 1
        o2      = iota					// 2
        o3								// 3
    )

    届时,iota 项及其之后未赋值的项的值,等于其声明位置的编号(从 0 开始计数)的值

    iota 只能对常量声明块中的常量进行赋值

  • 在 Go 语言中,不要求常量首字母大写。首字母的大小写是决定标识符的访问范围。

1.5 数据类型

每一种数据都定义了明确的数据类型,在内存中分配了不同大小的空间

- 基本数据类型

  • 数值型
    • 整数类型(int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, rune, byte)
    • 浮点类型(float32, float64)
  • 字符型(没有专门的字符型,使用 byte 保存单个字符)
  • 布尔型(bool)
  • 字符串(string)

- 派生 / 复杂数据类型

  • 指针(Pointer)
  • 数组
  • 结构体(struct)
  • 管道(Channel)
  • 函数
  • 切片(slice)
  • 接口(interface)
  • map

1.5.1 整数类型

用于存放一个整数数值

uint 为无符号整数,int 为有符号整数。

数字为占用空间大小。int8 占用 1 字节,int16 占用 2 字节,以此类推。

表数范围由其符号有无及占用空间决定。int8 表数范围是 [-128, 127],int32 表数范围是 [-231, 231 - 1],uint8 表数范围是 [0, 255]

rune 等价于 int32,其可以表示一个 Unicode 码

byte 等价于 uint8。存储字符时,选用 byte

整数类型的默认值(零值)是 0

#使用细节

  1. Go 各整数分为有符号和无符号。Go 中的 int、uint 的大小和操作系统有关。
  2. Go 的整型默认声明为 int 型
  3. 使用 unsafe.Sizeof(n) 函数,以查看变量占用空间的大小(字节)
  4. 使用整型变量时,应在保证程序正确运行的情况下,尽量使用占用空间小的数据类型

1.5.2 浮点类型

用于存放一个小数数值

数字为精度大小。float32 为单精度(32 位,占用 4 字节),float64 为双精度(64 位,占用 8 字节)

浮点类型的默认值(零值)是 0

#使用细节

  1. Go 的浮点型默认声明为 float64 类型
  2. 浮点数在计算机中的存放方式:浮点数 = 符号位 + 指数位 + 尾数位
  3. 尾数部分可能丢失,就会造成精度丢失。

1.5.3 字符类型

Go 没有专门的字符型,使用 byte 保存单个字符。Go 的字符串是由字节连接起来的。

字符常量是单引号 ‘ ’ 包括的单个字符。Go 运行使用转义字符

#使用细节

  1. 如果字符在 ASCII 表中,可以直接保存到 byte(或者 rune)

  2. 如果字符码值大于 255,可以使用 int 保存

  3. Go 中,字符的本质是一个整数。直接输出时,输出该字符的 UTF-8 码值

    要按照字符方法输出时,应该使用格式化输出 fmt.Printf()

    var i int = '★'
    fmt.Printf("%c", i)
  4. Go 语言的字符使用 UTF-8 编码。

  5. 字符类型可以进行运算,因为其相当于一个整数。

1.5.4 布尔类型

布尔类型用于表示真或假。布尔类型只允许取 true 或 false

bool 类型占 1 字节。其适用于逻辑运算,一般用于程序流程控制

布尔类型的默认值(零值)是 false

1.5.5 字符串类型

Go 语言将字符串也视为基本数据类型

字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串由单个字节连接

字符串的默认值(零值)是空串 “”

字符串有 2 种表示形式

  • 双引号包含字符串。此时会识别转义字符

    var str1 = "放牛的"
  • 反引号包含字符串。此时将以字符串的原生形式输出,包含换行和特殊字符。

    var str2 = `矮堇瓜`

    这样能实现防止攻击、输出原代码等效果

#使用细节

  1. Go 使用 UTF-8 编码标识 Unicode 文本,这样 Go 统一使用 UTF-8 编码,再也不会发生乱码问题。

  2. 字符串一旦赋值即不能更改。在 Go 中,字符串是不可变的

  3. + 运算符两侧都是字符串时,Go 会将其解析为字符串拼接

    一次拼接太长时,能分行编写,但需要把那个 + 运算符留在行尾

    var str = "马冬什么?\n" + "马冬梅!\n" +
    		"马什么梅啊?\n" + "马冬梅啊!\n" +
    		"什么冬梅啊?\n" + "行,大爷你坐这吧\n" + "好嘞"

    这是因为 Go 会自动为每行代码添加 ;。看到有 +,他就懂了!

1.5.6 基本数据类型的转换

Go 中的基本数据类型 不能自动转换,不同变量间赋值时需要显式转换

var d float64 = 10
var i int = int(d)		// 数据类型(变量)

#使用细节

  1. 数据类型既可以从小到大转换,也能从大到小转换

  2. 被转换的是变量存储的数值。变量本身没有变化

  3. 从大到小转换时,可能产生数据溢出

    var n int32 = 12
    var i int8 = int8(n) + 127			// 相当于 int8(n + 127) 结果会溢出
    /* var i2 int8 = int8(n) + 128 */	// 编译错误,因为检测到 128 超出范围

1.5.7 基本数据类型与 string 的转换

基本数据类型转成 string:

  • 使用 fmt.Sprintf("%参数", 表达式)

    var n = 100
    var c rune = '★'
    str := fmt.Sprintf("%c刻晴%c%v%c", c, c, n, c)	// ★刻晴★100★
  • 使用 strconv 包的函数

    var n int = 100
    str := strconv.FormatInt(int64(n), 2)			// 转化为 2 进制 1100100
    str2 := strconv.Itoa(n)

string 转成基本数据类型:

  • 使用 strconv 包的函数

    str := "100"
    var n int64
    n, _ = strconv.ParseInt(str, 8, 10)		// 该函数有多个返回值,_ 即忽略第二个

    此时,要确保那个 string 可以转化成有效数据。不能转换时,那个返回值是默认值

1.6 值类型和引用类型

  • 值类型:包括基本数据类型、数组、struct 结构体。

    对于值类型,其变量直接存储值,内存通常在栈中分配

  • 引用类型:包括指针、slice 切片、map、管道 chan、interface 等

    引用类型变量存储一个地址,该地址指向的空间真正的存储数据。内存通常在堆上分配。

    当没有任何变量引用该地址时,该地址对应的数据空间成为垃圾,由 GC 回收

1.6.1 指针

值类型都有对应的指针类型。

  • 声明指针:指针变量名 *数据类型
  • 记录地址:指针变量名 = &变量名
  • 使用指针:*指针变量名
var i int = 10;
var pointer *int = &i				// 指针
fmt.Println(pointer)				// 输出一个地址
fmt.Println(*pointer)				// 输出 10

1.7 标识符

Go 对各种变量、方法等命名时使用的字符序列称为标识符。凡能自己起名字的地方都叫标识符

#命名规则:

  • 标识符由 26 个大小写英文字母、数字、下划线组成
  • 数字不能作为标识符开头
  • Go 中严格区分大小写
  • 标识符不能包含空格
  • 下划线 _ 在 Go 中是一个特殊的标识符,称为 空标识符。它可以代表其他任何标识符,但其对应的值会被忽略(如,忽略一个返回值)。空标识符只能作为占位符使用,而不能作为标识符使用。
  • 不能以系统保留关键字作为标识符,如 break、if 等
  • 如果变量、函数、常量名首字母大写,则其可以跨包访问。否则仅限于本包访问

#命名规范:

  • 命名包名时:保持 package 名字与目录名保持一致,并使包名简短、有意义,且不和标准库冲突。
  • 命名变量、函数、常量时,采用驼峰法命名(即:单词字母小写,第二个单词起首字母大写)

#Go 的保留关键字和预定义标识符:

Go 为了简化代码编译过程中对代码的解析,其保留关键字只有 25 个:

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

其还提供了 36 个预定义标识符,包括基础数据类型和系统内嵌函数:

append bool byte cap close complex
complex64 complex128 uint16 copy flase float32
float64 imag int int8 int16 int32
uint32 int64 iota len make new
nil panic uint64 print println real
recover string true uint uint8 uintprt

<Go>1 Go 基础知识
https://i-melody.github.io/2022/06/05/Go/1 Go 基础知识/
作者
Melody
发布于
2022年6月5日
许可协议