Go语言学习二——牛刀小试
Posted 自由水鸟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言学习二——牛刀小试相关的知识,希望对你有一定的参考价值。
中我们了解了Go语言的诞生历程以及核心特性,今天我们就来一起尝试使用Go语言来做基础的编程。
说到编程,总是离不开变量、流程控制、函数这3者。我们首先看一下Go语言中的变量、流程控制、函数有什么特别之处,最后以二分查找为例体验Go语言基础编程。本文假设你已经安装好了Go开发环境,有关这一点,可以参考网上的教程。
变量
变量声明
Go语言中的变量声明采用变量名在前,类型在后的方式,如下:
var number int32
关于为什么不采用类似C语言中类型在前,变量名在后的方式(例如:int number
),Go语言的作者之一Rob Pike曾经写过一篇文章解释:Go's Declaration Syntax ,这么做主要是为了提高可读性,因为这样就可以从左到右的阅读变量或函数声明了,上述定义可以理解为:定义一个变量number,它的类型是int32。
变量赋值
定义好变量后,直接用=
赋值即可,例如:
number = 13
此外,Go还提供了一种简便的写法在变量声明的同时进行赋值:
number := 13
:=
将声明一个变量,并用指定的值为变量赋值,神奇之处在于不用声明变量类型,系统将自动识别右侧值的类型。
变量类型
基础变量类型如下:
整型:int,int8,int16,int32,int64,byte,uint等
浮点型:float32,float64
布尔型:bool
字符串:string
字符类型:rune
错误类型:error
复合类型如下:
指针:如var p *int
,则变量p即被定义为一个指向整型变量的指针
数组:如var matrix [3][5]int
,则变量matrix被定义为一个二维数组,用于表示一个3行5列的矩阵
切片:如var matrix [][]int
,注意与数组定义的区别,定义数组时必须指定数组的长度,且定义之后不可改变,切片则可以理解为是变长的数组
字典:如var ageMap map[string] int
定义了一个key为string类型,value为int型的字典
通道:chan,FIFO队列
结构体:struct,类似于c语言中的结构体
接口:interface,面向对象中定义抽象接口
从以上类型设置我们可以看出,Go语言的内置类型还是很丰富的,而且将其他语言通过类库提供的类型例如error、string、chan直接以关键字方式提供,方便程序员使用。
流程控制
判断
判断语句并没有什么特别之处,稍有不同的地方是,允许在条件语句中包含变量初始化操作,例如:
// 生产一个0-10之间的随机整数,并判断大小
if number := rand.Intn(10); number >= 5 {
fmt.Printf("got a big number %d", number)
} else {
fmt.Printf("got a small number %d", number)
}
选择
Go语言同样提供了灵活的选择分支表现,如下:
switch animal {
case "dog":
fmt.Printf("wang wang")
case "cat":
fmt.Printf("miao miao")
case name[:2]:
fmt.Printf("ge ge")
default:
fmt.Printf("wa wa")
}
可以看出,分支中可以使用一些表达式,从而提高灵活性的表达。
循环
Go语言只提供for循环,而不提供while循环,但是for循环的写法却非常灵活,这非常符合Go语言的设计思想:不必要的就不提供,必要的会非常强大灵活。
// 普通的for循环
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// 初始化多个值
for i, j := 0, 0;i + j < 10; i, j = i +1, j + 2{
fmt.Println(i, j)
}
i, j := 0, 10
// 类似于while循环,没有任何条件,无限循环
for {
if (i > j) {
break
} else {
fmt.Println(i, j)
i = i + 2
j = j + 1
}
}
函数
函数的定义使用关键字func
,然后声明参数列表,返回值放到最后:
func hello(name string) string {
return "hello, " + name
}
Go支持函数返回多个值,典型的用法如下:
// 接收一个参数name,返回两个值:第一个是string,第二个是error类型
func hello(name string) (string, error) {
// 如果name为空字符串,则返回错误
if name == "" {
return "", errors.New("name is nil")
} else {
return "hello, " + name, nil
}
}
func main() {
result, err := hello("peter")
// 如果err不为nil,说明函数返回错误,打印错误信息
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
函数还支持不定参数:
// printNames方法可以接收任意多个string类型的参数
func printNames(names ...string) {
// range函数返回两个值,第一个是下标,第二个是值,_为匿名变量
for _, name := range(names) {
fmt.Println(name)
}
}
值传递
在使用Go语言的函数时,我们需要注意,在Go语言中,参数的传递为值传递,不管是基础类型(如整型、浮点型等),还是复合类型(数组、结构体等),都是值传递,也就是说,在函数中会把参数拷贝一遍,然后在函数体中使用参数的拷贝,而不会改变参数的值。
看一个例子:
func addItems(array []int) {
array = append(array, 5, 6, 7)
}
func main() {
array := []int{0, 1, 2, 3, 4}
fmt.Println(array)
addItems(array)
fmt.Println(array)
}
执行程序,我们将得到如下结果:
[0 1 2 3 4]
[0 1 2 3 4]
这样做其实有很多好处,首先是安全,函数调用时无法修改参数值;其次是降低代码的复杂度,不用再做一些额外的操作去保存原始值。
当然,Go也提供来在函数中修改变量的方式,那就是借助指针:
func addItems(array *[]int) {
*array = append(*array, 5, 6, 7)
}
func main() {
array := []int{0, 1, 2, 3, 4}
fmt.Println(array)
addItems(&array)
fmt.Println(array)
}
再执行一遍,结果如下:
[0 1 2 3 4]
[0 1 2 3 4 5 6 7]
Go实现二分查找
// 二分查找,如果找到返回元素下标;如果没有找到返回-1
func binarySearch(array []int, target int) int {
for head, tail := 0, len(array) - 1; head <= tail; {
middle := (head + tail) / 2
if array[middle] == target {
return middle
} else if array[middle] > target {
tail = middle -1
} else {
head = middle + 1
}
}
return -1
}
func main() {
array := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(array)
if result := binarySearch(array, 7); result == -1 {
fmt.Println("can not find number 7 in array")
} else {
fmt.Printf("find number 7 in array,index = %d", result)
}
}
参考资料
《Go语言编程》
https://blog.golang.org/gos-declaration-syntax
以上是关于Go语言学习二——牛刀小试的主要内容,如果未能解决你的问题,请参考以下文章