700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Go语言基础语法讲解与学习

Go语言基础语法讲解与学习

时间:2024-06-30 06:21:29

相关推荐

Go语言基础语法讲解与学习

Go语言基础语法讲解与学习

1 Go语言基础知识介绍

​ 介绍Go语言之前,我们先了解一下有哪些开源项目是Go语言开发的,其中就包括 Docker、Go-Ethereum、Thrraform 和 Kubernetes。

​ Go语言经过了十几年的发展与成长,已经得到了不断的完善和优化。所以对于像我们这样想学习goalng的入门初学者来说,只要保持正确的学习方向和路径,我们的学习成果一定能够得到证明我们的努力和付出是值得的!

​ 另外说下学习golang的一些个人感受:golang在某些地方很像C语言,所以如果你已经掌握了C语言或其它编程语言,那么你能够很快的掌握golang的一些基础运用。并且你会在对golang的一些指针操作、内存分配以及多协程处理上有更深的认识和体会。但是在日后的项目设计上,建议可以先尝试以golang的设计思想去实现一些功能设计,而不要代入C的一些设计思想。如果你没有学习过C语言或者其他编程语言,golang作为你的第一入门语言来说也不会非常困难,因为它的语法和规则以及设计思想已经帮助你解决了很多问题,而你只需要把大部分精力用来进行代码设计。但是,请不要放弃对底层原理的学习和探索,这样你才能够对golang掌握的更加熟练。

1.1 Go语言设计的由来

​ Go语言出自 Ken Thompson 和 Rob Pike、Robert Griesemer 之手,他们都是计算机科学领域的重量级人物。

Ken Thompson

贝尔实验室 Unix 团队成员,C语言、Unix 和 Plan 9 的创始人之一,在 20 世纪 70 年代,设计并实现了最初的 UNIX 操作系统,仅从这一点说,他对计算机科学的贡献怎么强调都不过分。他还与 Rob Pike 合作设计了 UTF-8 编码方案。

Rob Pike

Go语言项目总负责人,贝尔实验室 Unix 团队成员,除帮助设计 UTF-8 外,还帮助开发了分布式多用户操作系统 Plan 9、Inferno 操作系统和 Limbo 编程语言,并与人合著了《The Unix Programming Environment》,对 UNIX 的设计理念做了正统的阐述。

Robert Griesemer

就职于 Google,参与开发 Java HotSpot 虚拟机,对语言设计有深入的认识,并负责 Chrome 浏览器和 Node.js 使用的 Google V8 JavaScript 引擎的代码生成部分。

​ 其实Golang的诞生初衷是为了满足Google本身的需求,但是这门语言的设计却融合了Go语言团队多年的经验和对编程语言设计的深入认识。设计团队借鉴了 Pascal、Oberon 和C语言的设计智慧,同时让Go语言具备动态语言的便利性。

​ Go语言的所有设计者都说,设计Go语言是因为 C++ 给他们带来了挫败感。在 Google I/O 的 Go 设计小组见面会上,Rob Pike 是这样说的:

我们做了大量的 C++ 开发,厌烦了等待编译完成,尽管这是玩笑,但在很大程度上来说也是事实。

1.2 Go 是编译型语言

​ Go 使用编译器来编译代码。编译器将源代码编译成二进制(或字节码)格式;在编译代码时,编译器检查错误、优化性能并输出可在不同平台上运行的二进制文件。要创建并运行 Go 程序,程序员必须执行如下步骤。

(1)使用文本编辑器创建 Go 程序;

(2)保存文件;

(3)编译程序;

(4)运行编译得到的可执行文件。

​ 这不同于 Python、Ruby 和 JavaScript 等语言,它们不包含编译步骤。Go 自带了编译器,因此无须单独安装编译器。

1.3 Go工程结构

一个Go语言项目的目录一般包含以下三个子目录:

src 目录:放置项目和库的源文件;pkg 目录:放置编译后生成的包/库的归档文件;bin 目录:放置编译后生成的可执行文件。

三个目录中我们需要重点关注的是 src 目录,其他两个目录了解即可,下面来分别介绍一下这三个目录。

src 目录

​ 用于以包(package)的形式组织并存放 Go 源文件,这里的包与 src 下的每个子目录是一一对应。例如,若一个源文件被声明属于 log 包,那么它就应当保存在 src/log 目录中。

​ 并不是说 src 目录下不能存放 Go 源文件,一般在测试或演示的时候也可以把 Go 源文件直接放在 src 目录下,但是这么做的话就只能声明该源文件属于 main 包了。正常开发中还是建议大家把 Go 源文件放入特定的目录中。

​ 包是Go语言管理代码的重要机制,其作用类似于Java中的 package 和 C/C++ 的头文件。Go 源文件中第一段有效代码必须是package <包名>的形式,如 package hello。

​ 另外需要注意的是,Go语言会把通过go get命令获取到的库源文件下载到 src 目录下对应的文件夹当中。

pkg 目录

​ 用于存放通过go install命令安装某个包后的归档文件。归档文件是指那些名称以“.a”结尾的文件。

​ 该目录与 GOROOT 目录(也就是Go语言的安装目录)下的 pkg 目录功能类似,区别在于这里的 pkg 目录专门用来存放项目代码的归档文件。

​ 编译和安装项目代码的过程一般会以代码包为单位进行,比如 log 包被编译安装后,将生成一个名为 log.a 的归档文件,并存放在当前项目的 pkg 目录下。

bin 目录

​ 与 pkg 目录类似,在通过go install命令完成安装后,保存由 Go 命令源文件生成的可执行文件。在类 Unix 操作系统下,这个可执行文件的名称与命令源文件的文件名相同。而在 Windows 操作系统下,这个可执行文件的名称则是命令源文件的文件名加 .exe 后缀。

2 Go基本语法

2.1 变量

​ 数学课中我们知道变量表示没有固定值且可改变的数,计算机课中我们又了解到变量是一段或多段用来存储数据的内存。

​ 作为静态类型的Go语言来说,Go的变量总是有固定的数据类型,类型决定了变量内存的长度和存储格式。我们可以修改变量的变量值,但是无法更改变量的变量类型。

定义

关键字var用来定义变量,类型放在变量名的后面,例如:

var x int// go会在定义的时候自动初始化变量,int类型默认为0var y = true// 也可在定义的时候进行赋值,这里会自动推断出bool类型,并赋值turevar a,b,c string// 同时定义多个相同类型的变量var i,str = 1, "string"// 同时定义并初始化多个不同类型的变量// 一般会在多个变量需要定义时采用组的形式进行定义var (x inty = truea,b,c stringi,str = 1, "string")

​ 上面是一般的定义形式,我们可以放在开头进行变量定义。除了上面的定义方式外,golang还提供了一种简短模式进行变量定义,例如:

func main() {y := truei, str = 1, "string"}

​ 这种定义方式通过:=来进行定义,但是使用的时候一定需要主要以下几点:

(1)定义变量同时显式初始化。

(2)不能提供数据类型。

(3)只能在函数内部使用

​ 我们在使用上面这种定义方式的时候一定需要弄清楚变量的作用域,因为有时候变量名称相同,但是表示的作用域和含义是不同的。例如:

var gX = 100// 先定义一个int类型的全局变量gX,值是100func main () {fmt.Println(&gX, gX)// 打印gX变量的地址和值gX := "str"fmt.Println(&gX, gX)}/*输出:0xac0411000xc630040a10"str"对比内存地址和值就可以发现上面两个gX变量虽然名字相同,但是却是两个不同的变量。*/

​ golang里面还有一种匿名变量,当我们遇到一些没有名称的变量、类型或者方法的时候就能使用匿名变量来增强代码的灵活性。

​ 匿名变量的特点就是一个下划线__本身就是一个特殊的标识符,可以称作空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。例如:

func getNumber()(int,int){return 1, 100}func main() {num1, _ := getNumber()_, num100 := getNumber()fmt.Println(num1, num100)}/*输出:1 100这里的getNumber函数是拥有两个整数的返回值,所以每次调用的时候会返回1和100两个数值。当我们只想使用其中某一个数值时,我们就可以使用匿名变量来接收其中一个数值。*/

注意:匿名变量不占用内存空间,也不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用

作用域

一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域。

了解变量的作用域对我们学习Go语言来说是比较重要的,因为Go语言会在编译时检查每个变量是否使用过,一旦出现未使用的变量,就会报编译错误。如果不能理解变量的作用域,就有可能会带来一些不明所以的编译错误。

我们可以根据变量的位置不同,分为局部变量全局变量形式参数三个类型。

局部变量

声明在函数体内的变量我们称之为局部变量,它的作用域只在函数体内部,函数的参数和返回值变量都属于局部变量。了解C知识就知道,局部变量不是一直存在的,它只定义在它的函数被调用后存在,函数调用结束后这个局部变量就会被销毁掉。例如:

package mainimport ("fmt")// main函数体外部func main() {// main函数体内部// 我们在main函数体内部声明两个变量x,y并赋值x := 0y := 1// 声明一个num变量并将x和y的和赋值给numnum := x + yfmt.Printf(" x = ",x," y = ",y," num = ",num)}/*输出:x = 0 y = 1 num = 1这里面的x,y,num三个变量都属于局部变量*/

全局变量

​ 在函数体外声明的变量称之为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用“import”关键字引入全局变量所在的源文件之后才能使用这个全局变量。

​ 全局变量声明必须以 var 关键字开头,如果想要在外部包中使用全局变量的首字母必须大写

package mainimport ("fmt")// main函数体外部// 声明一个全局变量numvar num intfunc main() {// main函数体内部// 我们在main函数体内部声明两个变量x,y并赋值x := 0y := 1// 给全局num变量进行赋值num = x + yfmt.Printf(" x = ",x," y = ",y," num = ",num)}/*输出:x = 0 y = 1 num = 1这里面的x,y两个变量属于局部变量,num属于全局变量*/

Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑。

形式参数

​ 在定义函数时函数名后面括号中的变量叫做形式参数(简称形参)。形式参数只在函数调用时才会生效,函数调用结束后就会被销毁,在函数未被调用时,函数的形参并不占用实际的存储单元,也没有实际值。

​ 形式参数会作为函数的局部变量来使用。

package mainimport ("fmt")//全局变量 avar a int = 33func main() {//局部变量 a 和 bvar a int = 1var b int = 0fmt.Printf("main() 函数中 a = %d\n", a)fmt.Printf("main() 函数中 b = %d\n", b)c := sum(a, b)fmt.Printf("main() 函数中 c = %d\n", c)}func sum(a, b int) int {fmt.Printf("sum() 函数中 a = %d\n", a)fmt.Printf("sum() 函数中 b = %d\n", b)num := a + breturn num}/*输出:main() 函数中 a = 1main() 函数中 b = 0sum() 函数中 a = 1sum() 函数中 b = 0main() 函数中 c = 1*/

2.2 常量

​ 常量表示运行时恒定并且不可改变的值,通常是一些字面量。Go语言中使用关键字const来定义常量,用来存储这些不会改变的数据。

​ 常量值必须是在编译期就可以确定的字符、字符串、数字或布尔值。例如:

// 显式类型定义: const a string = "Hello"// 隐式类型定义的时候编译器可以根据变量值来推断其类型// 隐式类型定义:const a = "Hello"// 常量可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。正确做法:const b = 1+1错误做法:const b = getNumber()

​ 常量间的所有算术运算、逻辑运算和比较运算的结果也是常量,对常量的类型转换操作或以下函数调用都是返回常量结果:lencaprealimagcomplexunsafe.Sizeof

iota常量生成器

Go语言并没有明确意义上的enum枚举定义,不过我们可以借助iota标识符来实现一组自增常量值。例如:

const (x = iota // 0y // 1z // 2)const (_ = iota // 0KB = 1 << (10 * iota) // 1 << (10 * 1)MB // 1 << (10 * 2)GB // 1 << (10 * 3))

我们也可以在多个常量定义中使用多个iota,它们各自单独计数,但是需要确保每行常量的列数相同。例如:

const (_, _ = iota,iota*10//0, 0*10a, b//1, 1*10c, d//2, 2*10)

我们如果希望中断iota的自增,我们就需要显式恢复。同时如果后续又想使用iota,则后续自增是按照行序递增的,不像C语言的enum那样按上一取值递增。例如:

const (a = iota// 0b// 1c = 100// 100d// 100(iota自增中断,值同上一行常量右值表达式)e = iota//4(恢复iota自增,值按照行序递增,包括c、d)f// 5)

2.3 命名

​ 这里给一些命名建议:

Go的命名区分大小写,并且首字母大小写决定了其作用域。一般使用驼峰命名法。局部变量优先使用短名称。命名一般是由字母或者下划线开始,由多个字母、数字和下划线组合而成。不要使用保留关键字。不建议使用与预定义常量、类型、内置函数相同的名字。专有名词一般全部大写。

2.4 基本类型

引用类型

​ 引用类型特指slicemapchannel这三种预定义类型。

​ 引用类型拥有更复杂的存储结构,除了分配内存以外,它们还须初始化一系列的属性,例如:指针、长度,甚至包含哈希分布、数据队列等。

​ 内置函数new可以按照指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。而引用类型必须使用make函数创建,编译器会将make转换为目标类型专用的创建函数(或指令),以确保完成全部内存分配和相关属性初始化。

整数类型

​ Go语言的数值类型分为以下几种:整数、浮点数、复数,其中每一种都包含了不同大小的数值类型,例如有符号整数包含int8int16int32int64等,每种数值类型都决定了对应的大小范围和是否支持正负符号。

​ 大多数情况下,我们只需要 int 一种整型即可,它可以用于循环计数器(for 循环中控制循环次数的变量)、数组和切片的索引,以及任何通用目的的整型运算符,通常 int 类型的处理速度也是最快的。

浮点数类型

​ Go语言提供了两种精度的浮点数float32float64,它们的算术规范由IEEE754浮点数国际标准定义,该浮点数规范被所有现代的 CPU 支持。

​ 一个float32类型的浮点数可以提供大约 6 个十进制数的精度,而float64则可以提供约 15 个十进制数的精度,通常应该优先使用float64类型,因为float32类型的累计计算误差很容易扩散,并且float32能精确表示的正整数并不是很大。

复数类型

​ Go语言中复数的类型有两种,分别是complex128(64 位实数和虚数)和complex64(32 位实数和虚数),其中complex128为复数的默认类型。

​ 复数的值由三部分组成RE + IMi,其中RE是实数部分,IM是虚数部分,REIM均为float类型,而最后的i是虚数单位。

​ 对于一个复数z := complex(x, y),可以通过Go语言的内置函数real(z)来获得该复数的实部,也就是 x;通过imag(z)获得该复数的虚部,也就是 y。

布尔类型

​ 一个布尔类型的值只有两种:truefalse。if 和 for 语句的条件部分都是布尔类型的值,并且==<等比较操作也会产生布尔型的值。

​ 布尔型无法参与数值运算,也无法与其他类型进行转换。

字符串类型

​ 字符串是一种值类型,且值不可变,即创建某个文本后将无法再次修改这个文本的内容,更深入地讲,字符串是字节的定长数组。

​ 可以使用双引号""来定义字符串,字符串中可以使用转义字符来实现换行、缩进等效果,常用的转义字符包括:

\n:换行符\r:回车符\t:tab 键\u\U:Unicode字符\\:反斜杠自身

字符类型

字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。

Go语言的字符有以下两种:

一种是uint8类型,或者叫byte型,代表了 ASCII 码的一个字符。另一种是rune类型,代表一个UTF-8字符,当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型等价于int32类型。

类型转换

​ Go语言不存在隐式类型转换,因此所有的类型转换都必须显式的声明:valueOfTypeB = typeB(valueOfTypeA)

​ 只有相同底层类型的变量之间可以进行相互转换(如将int16类型转换成int32类型),不同底层类型的变量相互转换时会引发编译错误(如将bool类型转换为int类型)。

2.5 关键字

​ 关键字即是被Go语言赋予了特殊含义的单词,也可以称为保留字。

​ Go语言中的关键字一共有 25 个:

​ 之所以刻意地将Go语言中的关键字保持的这么少,是为了简化在编译过程中的代码解析。和其它语言一样,关键字不能够作标识符使用。

标识符

​ 标识符是指Go语言对各种变量、方法、函数等命名时使用的字符序列,标识符由若干个字母、下划线_、和数字组成,且第一个字符必须是字母。通俗的讲就是凡可以自己定义的名称都可以叫做标识符。

​ 标识符的命名需要遵守以下规则:

由 26 个英文字母、0~9、_组成;

不能以数字开头,例如var 1num int是错误的;

Go语言中严格区分大小写;

标识符不能包含空格;

不能以系统保留关键字作为标识符,比如 break,if 等等。

命名标识符时还需要注意以下几点:

标识符的命名要尽量采取简短且有意义;

不能和标准库中的包名重复;

为变量、函数、常量命名时采用驼峰命名法,例如stuNamegetVal

Go语言中还存在着一些特殊的标识符,叫做预定义标识符,如下表所示:

​ 预定义标识符一共有 36 个,主要包含Go语言中的基础数据类型和内置函数,这些预定义标识符也不可以当做标识符来使用。

2.6 运算符

​ 运算符是用来在程序运行时执行数学或逻辑运算的,在Go语言中,一个表达式可以包含多个运算符,当表达式中存在多个运算符时,就会遇到优先级的问题,此时应该先处理哪个运算符呢?这个就由Go语言运算符的优先级来决定的。

​ Go语言有几十种运算符,被分成十几个级别,有的运算符优先级不同,有的运算符优先级相同,请看下表。

注意:优先级值越大,表示优先级越高。

2.7 小结

​ 掌握基本的语法知识是学习一门语言的必经之路,基础的知识只要细细思考和琢磨就会引发出多种多样的思路和问题。我们探索和解决这些问题的过程就是在巩固基础与深入学习,基础打得牢才能事半功倍。

​ 本文参考并借鉴了雨痕大佬的《Go语言学习笔记》,有兴趣的可以去看看这本书。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。