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语言学习二——牛刀小试的主要内容,如果未能解决你的问题,请参考以下文章

windows通过Visual Studio Code中配置GO开发环境(转)

在Visual Studio Code中配置GO开发环境

你知道的Go切片扩容机制可能是错的

前端试题-小试牛刀

牛刀小试之Django二

小白自我提高学习设计模式笔记—装饰者模式在Android开发的小试