块
Go语言中,块是指在一对相匹配的花括号内的一系列(可能为空的)语句。
在源代码中除了显式的块,还有隐式的块:
- 全局块:涵盖了所有Go源码文本
- 包块:涵盖了一个包的所有Go源码文本
- 文件块:涵盖了在一个文件内所有Go源码文本
- 每个for、if、switch语句都视为它自身的隐式块
- switch、select语句的每个条件都是一个隐式块
块可以嵌套并影响作用域。关于作用域,我们留在后面讲解。
变量声明
变量是某个值的存储位置,而变量声明则创建了变量并将一个标识符(变量名)绑定到这个变量。
让我们先来看一段程序:
package main
import (
format "fmt" // 给fmt包设置别名为format
)
/*将0到100摄氏度每隔10度转换成华氏度并打印出来
C=5/9*(F-32)
*/
func main() {
var c,f int //c和f是整型,默认初始化为0
var lower, upper = 0, 100 // lower和upper分别初始化为0和100,都推导为整型
var step int = 10 // step是整型,初始化为10
for c = lower; c <= upper; c+=step {
f = c*9/5+32
format.Println(c,"\t",f)
}
}
Go语言中变量需要先声明再使用。变量声明的语法如下:
var 变量名{, 变量名} 类型名
或
var 变量名{, 变量名} [类型名]= 初始值{,初始值}
- 在变量声明中如果指定了初始值列表,则初始值列表数量必须与变量名列表数量一致。
- 在变量声明中如果指定了类型名,则变量名列表中的所有变量都是所指定的类型,如果没有指定初始值列表,则初始值是所指定类型的“零值”;如果指定了初始值列表,则初始值的类型必须是所指定的类型。
关于类型的“零值”,将在数据类型一章中分别讲解,上面的例子中变量c和f都声明为int型,它们被初始化为int型的零值,即数值0。 - 在变量声明中如果没有指定类型名,则变量名列表中的各变量类型分别由初始值列表类型推导而来。
关于类型推导,也将留在后面讲解,上面的例子中变量lower和upper的类型分别由0和100推导得到,均为int型。 - 在同一级别块内,变量不能被重新声明。
短式变量声明
在函数体的内部(只能在函数体内部)还可以使用短式变量声明,语法如下:
变量名{, 变量名} :=初始值{,初始值}
变量名列表中的各变量类型分别由初始值列表类型推导而来;初始值列表数量必须与变量名列表数量一致。
它相当相于常规变量声明:
var 变量名{, 变量名} = 初始值{,初始值}
在同一级块中,如果已经声明过的变量与至少一个新变量一同出现在短式变量声明的变量列表中,则被声明过的变量以可被重新声明,但不能改变类型(其实质是对旧变量赋新值):
var i int =0
i,j := 1,1.0 // i的新值为1,也是整型,声明了新变量j,值为1.0是个浮点型
i,k := 1.0,1 // 编译错误,1.0是浮点型,i的类型是整型,不能重新声明为浮点型
请思考,在下面例子中,程序结束时c的值是什么?请注意理解“块”的概念。
package main
import (
format "fmt" // 给fmt包设置别名为format
)
func main() {
var c, f = 1, 1.0
for c := 0; c <= 300; c += 20 {
f = float64(c)*9/5 + 32
format.Println(c, "\t", f)
}
}
常量声明
在程序中不希望被改变的值可以声明为常量,常量声明的语法我们通过下以的示例来学习:
const a, b int = 0, 1 //a和b是int型常量,值分别为0和1
const c, d = "test", "string" //c和d是字符串型常量,值分别是test和string
const (
i, j float32 = 1.1, 2.1 //i和j是float32型常量,值分别是1.1和2.1((iota值为0,无用))
m, n = iota, iota //m和n是整型常量,值分别是iota值1和1
o, p //o和p以上一行为模板,是整型常量,值分别是iota值2和2
q, r = 1, 1 //q和r是整型常量,值分别是1和1,(iota值为3,无用)
s, t //s和t以上一行为模板,是整型常量,值分别是1和1(iota值为4,无用)
u, v = iota, iota //u和v是整型常量,值分别是iota值5和5
k, l //k和l以上一行为模板,是整型常量值分别是iota值6和6
w, x = "test2", "string2" //w和x是字符串常量,值是test2和string2
y, z //y和z以上一行为模板,是字符串常量,值是test2和string2
e // 错误,列表个数不同,不能以上一行为模板,应该要赋值
)
上面的示例展示了常量的声明方法,同时也展示了go语言预定义常量标识符iota的使用方法。
iota
iota 是个预定义整型常量,表示的是常量声明的当前索引值:
const A = iota // iota = 0
const B = iota // iota = 0
const (
C = -1 //iota=0,无用
D = iota // iota=1,所以D值为1
E,F = iota,iota // iota=2,所以E和F值都为2
)
函数
在之前的例子中我们已经接触过main函数。函数的作用就是完成某个特定的功能,main函数提供了我们所编写的程序的入口功能。
Go语言函数允许多个返回值,函数声明的基本语法:
func 函数名 (参数表) [(返回值表)][ {
函数体
}]
参数表与返回值表一起,构成函数签名。
参数表中的参数要么都有名字,要么都没有。同样的,返回值表中的返回值要么都有名字,要么都没有。例如:
// 函数名subStr,接受string型参数s以及int型参数offset和length,返回值是string型和error型
func subStr(s string, offset, length int, ) (string, error) {
return s, nil
}
如果返回值只有一个且返回值没有名字,则返回值列表的括号可以省略:
func fun1(s string) int
参数和返回值如果都有名字,它们的名字不能重复。例如下面的例子是错误的:
// 错误的例子,参数名和返回值名重复了
func fun2(s string) (s error)
给返回值命名的意义在于,可以使用无参数的返回语句,例如:
// 返回时不需要再为return语句指定参数
func SliceInfo(s []string) (length, capacity int) {
length = len(s)
capacity= cap(s)
return
}
// 返回值 i和j的零值是0,所以函数的返回值是0,0
func fun3(s string) (i,j int){
return
}
如果一个函数有返回值,则函数的所有执行路径的最后必须要有终止语句。
终止语句
- return或goto
- panic调用
- 在一个块的结尾遇到了终止语句
- 没有循环条件且break不会打断for循环的for语句
- 标识了终止语句的标签语句
关于panic、for语句和标签语句会在后续讲解。