您的位置:首页 > 编程语言 > Go语言

Go语言开发初探

2015-12-24 00:00 901 查看
摘要: Go语言弥补了C语言的不足并且保持了C的极简主义,专门针对多处理器系统编程进行了优化,使用Go语言除大幅度提升开发速度外,编译的程序还可媲美C或C++代码的速度,因此,可以将Go作为第一个学习的开发语言。

背景:Go语言是Google公司2009年推出的一种全新的静态编译型语言,目标是取代C、C++、Java作为系统开发的语言,经历了6年6次更新之后,最新版本为1.5,整个系统除一小部分由汇编完成外,其余都采用Go语言编写,语言日趋成熟。据笔者了解,国内知名IT公司如阿里、360、京东、小米、搜狗等都在积极尝试和使用,尤其是七牛云储存(http://qiniu.com)使用Go语言的比例为99.9%。多核和集群是互联网时代的典型特征,Go语言专门针对多处理器系统进行了优化,能更好的发挥多核性能,更安全高效的进行并发操作,因此,笔者决定尝试使用Go语言。 摘要:Go语言弥补了C语言的不足并且保持了C的极简主义,专门针对多处理器系统编程进行了优化,使用Go语言除大幅度提升开发速度外,编译的程序还可媲美C或C++代码的速度,因此,可以将Go作为第一个学习的开发语言。

关键词:Go,编程,并发,多核,网络

一、了解Go语言
按照Google公司Go语言创始人的话来说:我们之所以开发Go,是因为过去10多年间软件开发的难度令人沮丧。Go语言的开发效率不差于如Python等动态语言,同时又具备接近甚至达到C语言的执行效率。以下是笔者认为Go语言比较突出的几个优点:
1.跨平台支持,部署简单。Go语言可以在多个平台上进行编译,编译生成的是一个静态可执行文件,除了glibc外没有其他外部依赖,支持主流的32位和64位的x86平台,也支持32位的ARM架构,同时支持多种操作系统,不需要针对系统环境做额外的部署。
2.语言级别的原生并发机制。并发编程一直以来都是个非常困难的工作,但Go语言从语言层面上支持了并发,而这个也成为Go语言很重要的一个特性,在Go中并发程序依靠的是:goroutine(类似于线程)和channel。
3.高开发效率和高性能。Go语言语法简洁,开发效率可以和Python、Ruby等动态语言媲美,有完全的内存垃圾回收机制,最新的Go 1.5在程序的执行效率上已能达到C语言。
二、开发实战
(一)开发环境介绍
Go语言下载地址为:https://golang.org/dl/。


本次开发环境直接部署在Windows平台(win 10 10586版),最新Go语言版本为1.5.1,编译器使用的是较为流行的Sublime Text 3 + Gosublime ,当然还有一些辅助插件如:ConvertToUTF8,Alignment等,解决中文和代码对齐等功能。安装完成后可以通过在命令行输入go version查看是否安装成功。



环境配置好以后,首先通过一个Hello World,验证开发环境是否能成功运行:



(二)Go语言基础
1.Go语言中,声明变量时使用var关键字(类似JavaScript),变量的声明和定义有以下几种形式:



Go语言中进行变量申明时,如果不使用var关键字,可以使用更为简洁的:=符号,但需要注意的是var和:=不能同时使用。
Go语言中,如果一个变量没有被用到,GO的编译会报错,未使用引入的包也会报错。
2.Go语言所支持的一些常用基本数据类型如下:
类型
范围
bool
true,false
int8
-128 - 127
int16
-32768- 32767
int32
-2147483648-2147483647
int64
-9223372036854775808-9223372036854775807
uint8
0-255
uint16
0-65535
uint32
0-4294967295
uint64
0-188446744073709551615
string
float32
IEEE-754 32位浮点型数
float64
IEEE-754 64位浮点型数
在Go语言中,还有几个基本数据类型:byte、rune、int、uint、uintptr,其中byte类似uint8,rane类似int32,uint和int都是根据平台而定,一般为32位或者64位,而uintptr表示的是无符号整形,用于存放一个指针。
3.在Go语言中,if、while、for后面的条件表达式都没有小括号,而且第一个大括号不能换行,否则会报错,其实这一点习惯后也没有觉得有什么问题。

for j := 0; j < len(l); j++ {
if i == l[j] {
r = true
}
}

(三)Go语言特性探究
1.首先,写一个简单的Go程序,以便对Go语言有个更全面的认识,具体代码如下:

package main

import "fmt"
import "math/rand"
import "time"

//定义生成随机列表的大小
const MAXLEN = 10
//定义随机数生成范围
const MAXNUM = 100

//Go语言版冒泡排序
func bubblesort(intList []int, length int) {
if length > 1 {
for i := 0; i < length-1; i++ {
if intList[i] > intList[i+1] {
intList[i], intList[i+1] = intList[i+1], intList[i]
}
}
bubblesort(intList, length-1)
}
}
//确保生成的列表中没有重复数
func isExists(l []int, i int) bool {
r := false
for j := 0; j < len(l); j++ { if i == l[j] { r = true } }
return r
}
//生成乱序整数列表
func makeList() []int {
var intList []int
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; len(intList) < MAXLEN; i++ {
tmp := r.Intn(MAXNUM)
if !isExists(intList, tmp) {
intList = append(intList, tmp)
}
}
return intList
}

func main() {
//随机生成一个乱序的整数列表
intList := makeList()
fmt.Println("随机生成的乱序整数列表为:", intList)
bubblesort(intList, len(intList))
fmt.Println("乱序列表经过冒泡排序后:", intList)
}


运行程序后如下图(每次执行都会生成10个随机乱序数列):



在这段程序中,我们实现了Go语言版的冒泡排序,程序每次运行的时候,都是随机生成一个乱序的数列,然后再进行排序。在这里,我们可以看到if条件判断、for循环、整形数组等使用方式和语法。总的来看,还是比较简单。
2.多参数返回。在下面这段代码中,我们很简单快捷的实现了函数返回两个值。



3.Go语言接口编程。接口是Go语言中所有数据接口的核心,Go语言的主要设计者之一罗布.派克曾经说过,如果只能选择一个Go语言的特性移植到其他语言中,他会选择接口。在Go语言中,接口就是一大堆方法的集合。下面是一个Go语言官方关于接口的例子:
package main

import (
"fmt"
"math"
)

//定义一个简单的几何图形的接口
type geometry interface {
area() float64  //面积
perim() float64 //周长
}

//定义一个长方形
type rect struct {
width, height float64
}

//定义一个圆形
type circle struct {
radius float64 //半径
}

//计算长方形面积
func (r rect) area() float64 {
return r.width * r.height
}

//计算长方形周长
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}

//计算圆形面积
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}

//计算圆形周长
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}

func measure(g geometry) {
fmt.Println(g)
fmt.Println("面积:", g.area())
fmt.Println("周长:", g.perim())
}

func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}

measure(r)
measure(c)
}


在这个例子里,首先定义了一个关于几何图形的接口,作为例子,只包含了计算面积和周长的两个方法,下图是执行后的结果。



实现接口很简单,定义任意一个几何形状后,只要有area()和perim()这两个方法,就算是实现了上面的接口。例如我们想增加对三角形面积的计算,可以增加如下代码:
//定义三角形
type triangle struct {
side1, side2, side3 float64
}
//通过海伦公式计算三角形面积
func (t triangle) area() float64 {
hp := (t.side1 + t.side2 + t.side3) / 2
return math.Sqrt(hp * (hp - t.side1)(hp-t.side2)(hp-t.side3))
}
//计算三角形周长
func (t triangle) perim() float64 {
return t.side1 + t.side2 + t.side3
}


因为实现了geometry这个接口的两个方法:area和perim,因此我们可以直接调用measure来查看输出结果:



4.Go语言并发编程。在学习Go语言并发编程的时候,我们会学习两个新的感念,goroutine和channel。其中goroutine类似开辟一个新的线程,但是比线程还小,而且不受操作系统调度,用法极其简单(有的时候,越简单的东西,越容易让人犯糊涂),就是在调用的函数前加一个关键字“go”如:
func sayhello(){
//do something
}

go sayhello() //添加关键字go后,函数sayhello就作为goroutine去执行


举个例子,手头有一堆数据,需要经过超级复杂,超级耗时的计算才能得出答案。显然我们的主routine不可能只干这一件事,它还有其他事情需要处理。因此,我们开辟一个routine让其自个算去,而主程序将会继续执行。这里我们会发现,如果分配的routine计算出答案,如何回传给主routine使用呢?这时,channel就发挥应有的作用了。

Go语言使用channel接收或者发送特定类型的值,可以自己根据实际情况指定,比如两个routine之间相互传值为int类型,那么channel类型就可以设定为chan int,并且可以灵活的设置通道缓冲数据大小。
//通过make创建一个int类型channel
var c = make(chan int)
//或者不使用关键字
c1 := make(chan bool)

//向channel c 写入数据
c<-1
//从channel c中读取数据
<-c


下面来看一个具体例子:



这个是程序执行后结果:



如果在子routine执行的时候,主程序继续做别的事情,会是什么情况?



当然,这只是Go语言中并发编程最基础的用法实例,更多高级应用还需要继续深入学习。
四、总结
Go语言已经发布6年多,这几年,移动互联网飞速发展,Go语言也不断成长,并渐渐被各大公司认可。通过这次初探,我们也可以大概领略到Go语言的魅力,我认为可以利用这样一句广告语来概括:“简约但不简单”。是的,随着学习的深入,越来越发现Go语言的强大。

参考资料:

1.Https://gobyexample.com
2.许式伟 吕桂华.《Go语言编程》 人民邮电出版社
3.Rob Pike 《并发不是并行》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: