vlambda博客
学习文章列表

go语言打怪通关之 ⌈常量、变量、数据结构⌋


我是一名来自帝都985高校的机械研究生

本号专注于分享工科专业学习考试攻略程序员学习求职经验教师求职考试经验等相关内容,同时还会兼顾生活向,欢迎大家的关注和转发!


go语言打怪通关之 ⌈常量、变量、数据结构⌋


目录

常量

变量

    多重赋值

数据结构

    整型

    浮点型

    布尔类型

    字符串

    格式化字符串

字符类型

    数组

切片

常量

常量使用关键字 const 声明,下面有几个例子:

const limit = 512
const top uint16 = 1421
const Pi float64 = 3.1415926
const x,y int = 1,3 //多重赋值

Go 的常量定义可以限定常量类型,但不是必需的。如果定义常量时没有指定类型,那么该常量就是无类型常量,也叫字面常量

当需要设置多个常量的时候,不必重复使用 const 关键字,可以使用以下语法:

const (
    Cyan = 0
    Black = 1
    White = 2
)

Go 语言还预定义了这些常量:truefalseiota

iota 是一个可以被编译器修改的常量,「在 const 关键字出现时被重置为 0,在下一个 const 出现之前,每出现一次 iota,其所代表的数字自动加 1」。下面通过一个例子讲解 iota 的用法:

const (
    a = iota  //a == 0
    b = iota  //b ==1
    c = iota  //c == 2
)

const d = iota //d==0,因为const的出现,iota被重置为0

变量

变量是所有语言最基本和最重要的组成部分。Go 语言引入了关键字 var 对变量进行声明,也可以使用 := 来对变量直接进行初始化,Go 编译器会自动推导出该变量的类型,这大大的方便了开发者的工作。「需要注意的是 := 左侧的变量不能是已经被声明过的,否则会导致编译器错误」。

以下是 Go 声明和初始化变量的各种方法:

var a int
var b string
var c float64
var d [5] int  //数组
var e [] int   //数组切片
var f * int    //正确
var v1 int = 5 //正确
var v2 = 5     //正确,编译器自动推导出V2类型
v3 := 5        //正确,编译器自动推导出V3的类型

多重赋值

Go 语言提供了大多数语言不支持的多重赋值,这使得变量的交换变得十分简单。下面通过一个例子来了解 Go 语言的多重赋值:

i := 2
j := 3
i, j = j, i  //交换i和j的值,此时i == 3,j == 2

这样的方式可以一行代码实现变量的交换,明显的减少代码的行数,而不需要像 C/C++ 那样引入一个中间变量。

数据结构

整型

Go 语言提供了 11 种整型,如下列表所示。

类型 说明
byte 等同于 uint8
int 依赖于不同平台下的实现,可以是 int32 或者 int64
int8 [-128, 127]
int16 [-32768, 32767]
int32 [-2147483648, 2147483647]
int64 [-9223372036854775808, 9223372036854775807]
rune 等同于 int32
uint 依赖于不同平台下的实现,可以是 uint32 或者 uint64
uint8 [0, 255]
uint16 [0, 65535]
uint32 [0, 4294967295]
uint64 [0, 18446744073709551615]
uintptr 一个可以恰好容纳指针值的无符号整型(对 32 位平台是 uint32, 对 64 位平台是 uint64)

C 语言中我们可以通过 sizeof 操作符查看类型的字节长度,在 Go 语言中可以通过 unsafe.Sizeof 函数进行。

浮点型

Go 语言提供了两种浮点类型和两种复数类型,具体如下:

类型 说明
float32 ±3.402 823 466 385 288 598 117 041 834 845 169 254 40x1038 计算精度大概是小数点后 7 个十进制数
float64 ±1.797 693 134 862 315 708 145 274 237 317 043 567 981x1038 计算精度大概是小数点后 15 个十进制数
complex32 复数,实部和虚部都是 float32
complex64 复数,实部和虚部都是 float64

布尔类型

Go 语言提供了内置的布尔值 true 和false。Go 语言支持标准的逻辑和比较操作,这些操作的结果都是布尔值。值得注意的地方是可以通过 !b 的方式反转变量 b 的真假。需要注意的是布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。实例代码如下:

var a bool
a = true
b := (2 == 3) //b也会被推导为bool类型

//错误示范
var b bool
b = 1 //编译错误
b = bool(1) //编译错误

字符串

Go 语言中的字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其它包括 XML 和 JSON 在内,也都使用该编码。

由于该编码对占用字节长度的不定性,Go 中的字符串也可能根据需要占用 1 至 4 个字节,这与其它语言如 C++、Java 或者 Python 不同。「Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。」

Go 语言中字符串的可以使用双引号 (") 或者反引号 (`) 来创建。

「双引号」用来创建可解析的字符串字面量,所谓可解析的是指字符串中的一些符号可以被格式化为其他内容,如 \n 在在输出时候会被格式化成换行符,如果需要按照原始字符输出必须进行转义。

「反引号」创建的字符串原始是什么样,那输出还是什么,不需要进行任何转义。以下是几个例子:

t1 := "\"hello\""             //内容: "hello"
t2 := `"hello"`               //内容:和t1一致
t3 := "\u6B22\u8FCE"          //内容:欢迎

Go 语言中的部分转义字符如下表所示:

转义字符 含义
\\ 表示反斜线
\' 单引号
\" 双引号
\n 换行符
\uhhhh 4 个 16 进制数字给定的 Unicode 字符

在 Go 语言中单个字符可以使用单引号 (') 来创建。在 Go 语言中,一个单一的字符可以用一个单一的 rune 来表示。这也是容易理解的,因为 Go 语言的字符串是 UTF-8 编码,其底层使用 4 个字节表示,也就是 32 bit。

在 Go 语言中,字符串支持「切片操作」,但是需要注意的是如果字符串都是由 ASCII 字符组成,那可以随便使用切片进行操作,但是如果字符串中包含其他非 ASCII 字符,直接使用切片获取想要的单个字符时需要十分小心,因为对字符串直接使用切片时是通过字节进行索引的,但是非 ASCII 字符在内存中可能不是由一个字节组成。

如果想对字符串中字符依次访问,可以使用 range 操作符。另外获取字符串的长度可能有两种含义,一种是指获取字符串的字节长度,一种是指获取字符串的字符数量。字符串支持以下操作:

语法 描述
s += t 将字符串 t 追加到 s 末尾
s + t 将字符串 s 和 t 级联
s[n] 从字符串 s 中索引位置为 n 处的原始字节
s[n:m] 从位置 n 到位置 m-1 处取得的字符(字节)串
s[n:] 从位置 n 到位置 len(s)-1 处取得的字符(字节)串
s[:m] 从位置 0 到位置 m-1 处取得的字符(字节)串
len(s) 字符串 s 中的字节数
len([]rune(s)) 字符串 s 中字符的个数,可以使用更快的方法 utf8.RuneCountInString()
[]rune(s) 将字符串 s 转换为一个 unicode 值组成的串
string(chars) chars 类型是 []rune 或者 []int32, 将之转换为字符串
[]byte(s) 无副本的将字符串 s 转换为一个原始的字节的切片数组,不保证转换的字节是合法的 UTF-8 编码字节

格式化字符串

Go 语言标准库中的 fmt 包提供了打印函数将数据以字符串形式输出到控制台、文件、其他满足 io.Writer 接口的值以及其他字符串。目前为止我们使用了 fmt.Printffmt.Println,对于前者的使用,就像 C 语言中的 printf 函数一样,我们可以提供一些格式化指令,让 Go 语言对输出的字符串进行格式化。同样的我们可以使用一些格式化修饰符,改变格式化指令的输出结果, 如左对齐等。常用的格式化指令如下:

格式化指令 含义
%% % 字面量
%b 一个二进制整数,将一个整数格式化为二进制的表达方式
%c 一个 Unicode 的字符
%d 十进制数值
%o 八进制数值
%x 小写的十六进制数值
%X 大写的十六进制数值
%U 一个 Unicode 表示法表示的整形码值,默认是 4 个数字字符
%s 输出以原生的 UTF-8 字节表示的字符,如果 console 不支持 UTF-8 编码,则会输出乱码
%t 以 true 或者 false 的方式输出布尔值
%v 使用默认格式输出值,或者使用类型的 String() 方法输出的自定义值,如果该方法存在的话
%T 输出值的类型

常用的格式化指令修饰符如下:

  • 空白 如果输出的数字为负,则在其前面加上一个减号 -。如果输出的是整数,则在前面加一个空格。使用 %x 或者 %X 格式化指令输出时,会在结果之间添加一个空格。例如 fmt.Printf("% X", "实") 输出 E5 AE 9E。
  • #
    • %#o 输出以 0 开始的八进制数据。
    • %#x 输出以 0x 开始的十六进制数据。
  • + 让格式化指令在数值前面输出 + 号或者 - 号,为字符串输出 ASCII 字符(非 ASCII 字符会被转义),为结构体输出其字段名。
  • - 让格式化指令将值向左对齐(默认值为像右对齐)。
  • 0 让格式指令以数字 0 而非空白进行填充。

字符类型

在 Go 语言中支持两个字符类型,一个是 Byte(实际上是 Unit8 的别名),代表 UTF-8 字符串的单个字节的值;另一个是 rune,代表单个 Unicode 字符。

处于简化语言的考虑,Go 语言的多数 API 都假设字符串为 UTF-8 编码。尽管 Unicode 字符在标准库中有支持,但实际很少使用。

数组

Go 语言的数组是一个定长的序列,其中的元素类型相同。多维数组可以简单地使用自身为数组的元素来创建。数组的元素使用操作符号 [ ] 来索引,索引从 0 开始,到 len(array)-1 结束。数组使用以下语法创建:

[length]Type
[N]Type{value1, value2, ..., valueN}
[...]Type{value1, value2, ..., valueN}

如果使用了 ...(省略符)操作符,Go 语言会为我们自动计算数组的长度。在任何情况下,一个数组的长度都是固定的并且不可修改。数组的长度可以使用 len() 函数获得。

由于数组的长度是固定的,因此数组的长度和容量都是一样的,因此对于数组而言 cap()len() 函数返回值都是一样的。数组也可以使用和切片一样的语法进行切片,只是其结果为一个切片,而非数组。同样的,数组也可以使用 range 进行索引访问。

切片

一般而言,Go 语言的切片比数组更加灵活,强大而且方便。「数组是按值传递的(即是传递的副本),而切片是引用类型」,传递切片的成本非常小,而且是不定长的。而且数组是定长的,而切片可以调整长度。创建切片的语法如下:

make([ ]Type, length, capacity)
make([ ]Type, length)
[ ]Type{}
[ ]Type{value1, value2, ..., valueN}

内置函数 make() 用于创建切片、映射和通道。当用于创建一个切片时,它会创建一个隐藏的初始化为零值的数组,然后返回一个引用该隐藏数组的切片。该隐藏的数组与 Go 语言中的所有数组一样,都是固定长度。

如果使用第一种语法创建,那么其长度为切片的容量 capacity;如果是第二种语法,那么其长度记为切片的长度 length。一个切片的容量即为隐藏数组的长度,而其长度则为不超过该容量的任意值。另外可以通过内置的函数 append() 来增加切片的容量。

这一节我们介绍 Go 语言基础的最后一个知识点——包。前面我们了解过 Go 语言组织代码的方式是包,包是各种类型和函数的集合。在包中,如果标示符(类型名称,函数名称,方法名称)的首字母是大写,那这些标示符是可以被导出的,也就是说可以在包以外直接使用。前面我们也提到了 GOPATHGOROOT` 目录中搜索包。

我们创建的自定义的包最好放在 GOPATH 的 src 目录下,每个包单独放在一个目录里,如果两个不同的包放在同一目录下,会出现名字冲突的编译错误。作为惯例,包的源代码应该放在一个同名的文件夹下面。同一个包可以有任意多的源文件,文件名的名字也没有任何规定。

go语言打怪通关之 ⌈常量、变量、数据结构⌋



我是一名来自帝都985高校的机械研究生

本号专注于分享工科专业学习考试攻略程序员学习求职经验教师求职考试经验等相关内容,同时还会兼顾生活向,欢迎大家的关注和转发!