2. 变量与简单数据类型

变量是编程的起始点,程序用到的各种数据都是存储在变量内的。在 Go 语言中,所有的变量需要通过声明才能使用。本章会详细介绍变量的使用方法以及数据类型,如整型、浮点型等其他基础数据类型,连接数据之间的是各种运算符号,本章会详细介绍基本的运算符,包括所有的算术运算符,以及功能丰富的位运算符、比较运算符、逻辑运算符,这些运算符是 Go 编程的基础。

2.1. 标识符

标识符是用来标识变量、类型、常量等语法对象的符号名称,一个有效的标识符应该遵循特定的命名规则,在 Go 语言中必须满足:

  • 只能由字母(A-Z, a-z)、数字(0-9)或下划线(_)组成
  • 必须以字母或下划线开头
  • 区分大小写
  • 不能与关键字或保留字相同

对于关键字以及其他的保留字在后面会有详细的介绍。

2.2. 单行和多行注释

在 Go 语言中,注释是用于对代码的解释和说明,以提高代码的可读性。Go 支持两种类型的注释:行注释和块注释。

2.2.1. 行注释

行注释使用 // 开头,适用于单行注释。

// 行注释
fmt.Println("Hello World!")

2.2.2. 块注释

块注释使用 /* */ 包围,适用于多行注释。

/*
块注释,
可以跨越多行
*/
fmt.Println("Hello World!")

2.3. 变量

Go 语言是静态类型的,变量必须先声明才能使用,变量声明时必须明确变量的类型。

2.3.1. 变量的声明

在变量的声明时,Go 语言的类型在变量后面。在 Go 语言中,使用关键字 var 声明一个变量,格式为:var identifier [type],如下:

var a int // 声明一个 int 类型变量
var b string // 声明一个 string 类型的变量

当同时声明多个变量时,可以将多个变量一起声明,如下:

var (
    a int
    b string
)

2.3.2. 变量的初始化

变量在声明后,要想使用,首先需要对其初始化,如下:

var a int // 声明一个 int 类型变量
a = 1 // 初始化变量

以上先声明后初始化也可以写成声明时同时赋值,这时候可以省略类型名,此时的变量会自动被确定为值的类型,如下:

var a = 1 // 简写:声明时赋值

解释一下,因为 1 是 int 类型,所以赋值时,a 自动被确定为 int 类型,所以类型名可以省略不写,这种方式还有一种更简单的表达:

a := 1
b := "Hello World!"

注:使用 := 可以最便捷的声明并同时初始化变量,但是注意,:= 只能声明并初始化从未声明过的变量,否则将会报错,如下:

var a int
a := 1

此时会报错:no new variables on left side of :=

2.4. 常量

常量是一种在程序运行时,不能被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。常量使用关键词 const 定义,常量的定义格式为:const identifier [type] = value

其中,类型说明符 [type] 是可以省略的,编译器可以根据变量的值来推断其类型。如:

const b string = "abc" // 显式类型定义
const b = "abc" // 隐式类型定义

同时,多个相同类型的声明可以简写为:

const a, b = value1, value2

2.5. 基础数据类型

在上面定义变量和常量时,已经接触到数据类型,通俗来讲,数据类型用于声明函数和变量,通过不同的数据类型为数据申请不同的内存大小。在 Go 语言中,数据类型包括:基础数据类型、复合数据类型、引用数据类型和接口数据类型。其中,基础数据类型包括:

  • 数字类型:包括整形 int 和浮点型 float
  • 布尔类型:类型为 bool,值只可以是常量 true 或者 false
  • 字符串类型:字符串就是一串固定长度的字符连接起来的字符序列。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。

本章中聚焦在基础的数据类型,字符串类型会单独在下一章节介绍。

2.5.1. 整型

除了通常使用的 int 类型之外,又可以根据可表示范围不一样细分为不同的类型:

int 类型根据机器是 32 位还是 64 位会自动转换成 int32 或者 int64,在实际的开发过程中,绝大部分情况下直接使用 int 就已经够用了。除了有符号的 int 外,还有无符号的 uint,如下:

2.5.2. 浮点型

与整型不一样,浮点数的类型只有 float32 和 float64,详细如下:

在实际的使用过程中需要根据需求选择合适的类型,这个有点类似于其他语言有 float 和 double 之分。除了 float32 和 float64 之外,Go 语言内置支持复数,详细如下:

在实际的开发过程中,复数类型使用的较少,只是在一些特殊的场景下,需要使用到复数类型,如信号处理,初始化复数类型的代码如下:

z := 3 + 4i
// 取实部
fmt.Println(real(z))
// 取虚部
fmt.Println(imag(z))

2.5.3. 其他数字类型

除了上述介绍的整型和浮点型,还有其他的数字类型,具体如下:

这些类型的使用方法在后面章节中将会详细介绍。

2.5.4. 布尔型

布尔类型为 bool,布尔类型的值只有 true 和 false 两种,可配合条件语句一起使用。

var a bool
a = true
fmt.Println(a)

2.6. 运算符

有了基本的数据类型后,要实现多个数据之间的运算,就需要对应的运算符。运算符用于在程序运行时执行数学或逻辑运算。在 Go 语言中,内置的运算符有:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符

接下来让我们来详细看看各个运算符的介绍。

2.6.1. 算术运算符

算术运算符包括加、减、乘、除等,具体如下:

使用方法如下:

a := 10
b := 5
fmt.Printf("a + b = %d\n", a+b) // 15
fmt.Printf("a - b = %d\n", a-b) // 5
fmt.Printf("a * b = %d\n", a*b) // 50
fmt.Printf("a / b = %d\n", a/b) // 2
fmt.Printf("a %% b = %d\n", a%b) // 0
a++
fmt.Printf("a ++ = %d\n", a) //	11
b--
fmt.Printf("b -- = %d\n", b) // 4

2.6.2. 关系运算符

关系运算符是判断左右两个变量之间的关系,返回值是布尔类型,具体如下:

使用方法如下:

func main() {
    a := 10
    b := 5
    if a > b {
        fmt.Println("a is greater than b")
    } else {
        fmt.Println("a is not greater than b")
    }
}

2.6.3. 逻辑运算符

逻辑运算符用于操作 bool 类型的变量、常量或表达式,Go 语言中支持的逻辑运算符具体如下:

使用方法如下:

func main() {
	a := true
	b := false
	if a && b {
		fmt.Println("Both a and b are true")
	} else if a || b {
		fmt.Println("Either a or b is true")
	} else {
		fmt.Println("Both a and b are false")
	}
}

2.6.4. 位运算符

位运算符直接操作数值的原始 bit 位,Go 支持的位运算符有如下 6 个:

2.6.5. 赋值运算符

赋值运算符的作用是变量的赋值,可以将一个表达式赋值给一个变量,Go 语言中支持的赋值运算符如下所示:

2.6.6. 其他运算符

除了上述的各类运算符之外,还有取地址运算符、指针变量,具体如下:

使用方法如下:

a := 10
fmt.Println("address of a: ", &a) // 返回的是 a 的地址:0x453525496020
fmt.Println("value of a: ", *(&a)) // 通过 &a 获取 a 的地址,再通过 * 解引用获取 a 的值:10

2.6.7. 运算符优先级

有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由上至下代表优先级由高到低:

2.7. 本章小结

变量和数据类型构成了 Go 语言的基本组成部分,是最重要的基石,本章主要介绍了 Go 语言编程中的变量以及各种基本数据类型,包括各种数值型、bool 型等。连接不同数据的是各种运算符,在本章中介绍了 Go 中常用的算术运算符、位运算符、赋值运算符、比较运算符、逻辑运算符等,掌握这些运算符是 Go 编程的基础。