实践文章:Go 语言基础语法和常用特性解析 | 青训营

50 阅读5分钟

基础语法

语言结构

基础组成部分为:

  1. 包声明:源文件中非注释的第一行制命这个文件属于哪个包
  2. 引入包
  3. 函数
  4. 变量
  5. 语句&表达式
  6. 注释:可以使用//或者/*……*/,不可嵌套使用

包(package)

Go语言中的包和其他语言的库或模块的概念类似,目的都是为了支持模块化、封装、单独编译和代码重用。一个包的源代码保存在一个或多个以.go为文件后缀名的源文件中,通常一个包所在目录路径的后缀是包的导入路径。

如果一个名字是在函数内部定义,那么它就只在函数内部有效。如果是在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头的(译注:必须是在函数外部定义的包级名字;包级函数名本身也是包级名字),那么它将是导出的,也就是说可以被外部的包访问,例如fmt包的Printf函数就是导出的,可以在fmt包外部访问。包本身的名字一般总是用小写字母

变量

一般语法:

var 变量名字 类型 = 表达式

其中“类型”或“= 表达式”两个部分可以省略其中的一个。如果省略的是类型信息,那么将根据初始化表达式来推导变量的类型信息。如果初始化表达式被省略,那么将用零值初始化该变量。

  1. var a = "initial"会自动判断变量类型
  2. var b,c int = 1,2设定变量为int
  3. var d = true bool type
  4. var e float64 数字类型变量对应的零值是0,布尔类型变量对应的零值是false,字符串类型对应的零值是空字符串,接口或引用类型(包括slice、指针、map、chan和函数)变量对应的零值是nil。数组或结构体等聚合类型对应的零值是每个元素或字段都是对应该类型的零值。
  5. f := float32(e)
  6. const无明确类型,自动确定类型
  7. string 可以使用 + 来组合

if-else语句

if x != '!' {
    x := x + 'A' - 'a'
    fmt.Printf("%c", x) // "HELLO" (one letter per iteration)
}

类似C++但是条件没有括号,if与条件语句之间以空格隔开 { 必须在if语句之后

循环语句(只有for)

for init; condition; post { }

  • init一般是赋值表达式,给控制变量赋初值
  • condition关系表达式或逻辑表达式,循环控制条件
  • post一般为赋值表达式,给控制变量增量或减量

for语句执行过程如下:

  • 先对表达式 1 赋初值;
  • 判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

for可以出现如下情况:

  • for condition 相当于while
  • for 相当于无限循环

循环控制语句

  • break 经常用于中断当前 for 循环或跳出 switch 语句
  • continue 跳过当前循环的剩余语句,然后继续进行下一轮循环

range

数组可以返回索引以及其值,不需要索引可以用下划线例如for _, value = range list map会返回key, value

switch语句

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

类似C++但是不需要每个case里面的break

同时switch后可以是任意的数据类型甚至为空,所以可以用switch中case为条件语句来代替繁多的if-else语句

数组

数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。数组的长度是固定的每个元素可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数。默认情况下,数组的每个元素都被初始化为元素类型对应的零值

var a [3]int
var b := [3]int{1, 2, 3}
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2, 3} // r[3] = 0

在数组字面值中,如果在数组的长度位置出现的是“...”省略号,则表示数组的长度是根据初始化值的个数来计算。

q := [...]int{1, 2, 3}

切片

可变长度,支持make,append,copy,切片操作(类似python)

一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。

注意:s = append(s, "d")必须把结果赋值回原数组,因为slice的原理是储存长度+容量+指向数组的指针,当append超过容量时会扩容并返回一个新的slice

months := [...]string{1: "January", /* ... */, 12: "December"}

以上代码一月份是months[1],十二月份是months[12]。通常,数组的第一个元素从索引0开始,但是月份一般是从1开始的,因此我们声明数组时直接跳过第0个元素,第0个元素会被自动初始化为空字符串

map

在Go语言中,一个map就是一个哈希表的引用,map中元素无序,可以用内置的make函数创建一个mapages := make(map[string]int),或者如下:

ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}

这样可以获取map中是否有这个元素

r, ok := m["unkown"]
fmt.Println(r, ok) // 0 false

使用内置的delete函数可以删除元素:

delete(ages, "alice") // remove element ages["alice"]

函数

变量类型后置

多返回值,业务中常常是第一个为返回结果,第二个值为错误信息

func exists(m map[string], k string)(v string, ok bool){
	v, ok = m[k]
	return v, ok
}