在语法篇(一)中学习了go中基本的数据类型、变量、常量等组成语言的基本要素,在这一节中将会学习如何将这些元素组织起来,最终写成可以执行的代码。
在这一部分包括:
go中的流程控制语句;
go中函数的用法;
go特殊的错误处理方式;
Golang中的流程控制语句
在具体编程的时候免不了需要使用一些特殊的语句实现某些功能,比如使用循环语句来进行迭代,使用选择语句控制程序的执行方式等。这些语句在任何一门程序设计语言
中都会有支持,golang中除了支持常用的循环,条件选择语句以外,还支持跳转语句,下面分别看看这些语句的使用方式。
条件语句 if ,else if, else,...
用法:
if 表达式 { //注意花括号必须要和if 在同一行,包括下面的else 和 {也是;同时表达式不需要使用括号括起来
程序体 //且无论程序体有几行都需要有花括号,这是和 C 有区别的地方
. . .
} else {
程序体
. . .
}
注意,在if之后可以有表达式的赋值操作,之间使用分号隔开。
选择语句 switch
其实和if语句实现的功能类似,只是选择语句更加灵活并可以减少If else的分支开销,和C语言中的switch的使用类似,
switch 表达式 { //和if语句一样,表达式不需要使用括号,同时switch和 { 在同一行
case 条件一:
程序体
case 条件二:
程序体
case ...
default:
程序体
}
这里和C语言的一个很大不同是,在每一个case条件的程序体中不需要使用break来强制结束。如果需要执行下面的case语句,那么可以通过添加 fallthrough 关键字来实现。
循环语句for
go中同样支持循环语句,但是与C等其他语言不同的是,go中只支持for来实现循环,不支持使用while。
//使用方式一:最基本的用法
for 变量初始化; 循环结束条件; 变量变化表达式 {
程序体
...
}
//使用方式二: 无限循环的情况,类似于C中的for(;;)
for {
程序体
...
}
同时在for的表达式中允许使用平衡的多重赋值,例如下面的在go中将一个数组逆序的写法:
a := [] int {1,2,3,4,5,6}
for i, j := 0, len(a)-1; i<j; i, j = i + 1, j - 1 {
a[i], a[j] = a[j], a[i]
}
注意在go语言中也可以使用break语句。
跳转语句goto
作为初学者,我也不知道为什么Go语言会支持goto这种用法,在早年之前关于goto的弊端,已经被Dijkstra等人发文章集中讨论过,这里不做具体介绍,等以后深入学习之后再来补充,为什么设计者要这样来设计。
上面就是golang支持的四种程序控制语句,为了完成完整的代码,我们还需要函数来进行封装一些特定的功能,下面我们介绍golang中函数的使用方法。
Golang中函数的使用
函数的定义
与其它语言,例如C语言不同的是,Golang中函数的定义如下:
func关键字 函数名 (参数1,参数2,...) (返回值1,返回值2,...) {
函数体
...
}
// 例如下面的实现两个变量增加的函数:
func Add(a int, b int) (ret int, err error) {
return a+b, nil
}
如果返回值只有一个那么括号可省,如果多个参数的类型相同,那么可省去前面变量的类型。
函数的调用
函数调用的方式是先导入导入包,然后通过包的方式使用函数。
这里需要注意的是,函数名的大小写在golang中是有讲究的,只有大写字母开头的函数才能被其它包使用。而使用小些字母
开头的函数只能在本包内可见。变量名的命名规则类似。
不定参数的支持
在golang中函数同样支持不定参数,即函数可以接受任意类型,任意个数的参数。
例如下面的函数myfunc可以接受任意多个int型的变量作为参数:
func myfunc (args ...int) {
for _,arg := range args {
fmt.Println(arg)
}
}
//在调用时:
myfunc(2,3,4)
mufunc(1,3,7,13)
//如果支持任意类型的参数,那么只需要将int 换成 interface{} 就可以了
func MyPrintf (args ...interface{}) {
程序体
...
}
多返回值
之前已经介绍过了golang的函数是支持多返回值的,如果哪一个返回值是不需要的那么直接可以将对应的值设为缺省就可以了。
匿名函数以及闭包
如果是C或者C++程序员可能对匿名函数的概念比较陌生。因为在这些语言中并不支持匿名函数的概念,函数名是一个指针用来调用一个函数。
在go以及JavaScript,C#和Objective-C中都有很匿名函数的支持。
从函数的形式上来说,匿名函数是指在定义一个函数的时候不需要指出函数名。从使用上来说,我个人认为,匿名函数是为了更加灵活的使用函数的,因为在C,c++中
我们不能在一个函数中再定义另一个函数。而有的时候我们需要这样使用,所以匿名函数就可以实现这样的功能,在一个函数中通过不定义函数名的形式来定义一个匿名函数
,而这个匿名函数可以调用此函数外围函数的一些变量。其实这个就是闭包的功能。我们先来看一个匿名函数的定义形式,然后再介绍闭包的概念。
//定义一个实现两个数相加的匿名函数
func (a, b int) int {
return a+b
}
//我们可以把这个匿名函数赋值给一个变量,然后通过这个变量来调用匿名函数:
f := func(a, b int) int {
return a + b
}
//之后我们可以使用 f(x,y) 来调用 func
闭包
关于闭包如果之前没有什么概念的话,比如我,可以先看一下这个链接:http://ahomeeye.iteye.com/blog/1050178
下面是我个人的一点见解,其实简单来讲,
闭包就是一个代码块,而这个代码块可能就是一个匿名函数,类似于上面定义的,这个代码块的特殊的地方就是他可以使用于他在同一级环境中定义的变量。当然这个
只是我个人的一点理解而已。下面是七牛团队书中的一个例子:
package main
import (
"fmt"
)
func main() {
var j int = 5
a:= func() (func()) { //这里定义了一个闭包。由a指向这个闭包
var i int = 10
return func() {
fmt.Printf("i, j: %d, %d \n", i, j) //闭包中可以使用变量j
}
}()
j *= 2
a()
}
//执行结果是:
i , j : 10, 5
i, j : 10, 10
关于闭包更多的知识我们还是后面用到的时候再好好说说,这里只要明白这个概念就可以了。
下面来看看golang中的
错误处理
对错误的处理,可能出现异常的扑捉等是编写健壮性程序的关键。在golang中对错误的处理具有很好的支持,包括
error 接口
通过golang提供的error接口,用户可以自己定义error的类型,这里需要实现error接口的Error()方法。这些具体的实现细节到下面学习
golang的面向对象的时候再做介绍。
defer 关键字
defer,推迟延期的意思。在golang里面 在一个语句前加上defer可以保证在程序无论是正常退出还是异常终止的时候其修饰的语句部分都可以被执行。
一般在进行IO的时候需要关闭文件描述符的时候会用到。
比如:
defer file.close()
注意defer中的语句是以栈的形式组织的,最后声明的最先被调用。
最后说说panic() 和recover()
这是golang内置的两个函数用来报告和处理运行时错误 和 程序中的错误。
当调用 panic() 函数时,正常的函数执行流程将立即中止,但是使用defer关键字延迟执行的语句将正常展开。
recover 函数类似于高级程序设计语言中对异常的扑捉,在golang中使用recover() 函数可以截止并终止错误处理流程。
总结
以上就是语法篇(2)中学习的内容,主要是学习了golang中的流程控制语句,golang中函数的使用,以及错误的处理等。对于其中的一些特性有些并没有很深的体会,后面会加深学习。
By Lingtao Kong in Nanjing 2015/06/16 转载请注明出处:http://blog.csdn.net/michael_kong_nju/article/details/46507821