初识go语言


title: 初识go语言
tag:

  • golang
  • 编程语言
    categories: notes

简介

Go语言是一门全新的静态类型开发语言,与当前的开发语言相比具备众多令人兴奋不已的新特性。最主要的新特性如下:

  • 自动垃圾回收
  • 更丰富的内置类型
  • 函数多返回值
  • 错误处理
  • 匿名函数和闭包
  • 类型和接口
  • 并发编程
  • 反射
  • 语言交互性

自动垃圾回收

手动管理内存的一个问题就是由于指针的到处传递而无法确定何时可以释放该指针的指向的内存块。假如在代码中的某个位置我们释放了内存,而另一些地方还在使用指向这块内存的指针,那么这些指针就变成了所谓的野指针或者悬空指针,对这些进行任何读写操作都会导致不可预料的后果。就比如以下的c++代码,进行内存释放。

int *p = new int;
p +=10 ; //这里对指针进行了偏移,因此那块内存不再被引用
// ...... 这里可能发生针对这块int内存的垃圾回收。
p -=10; //居然又偏移到原来的位置
*p = 10; //如果有垃圾收集,这里就无法保证可以正常运行了

所谓的垃圾回收,即所有的内存分配动作都会被在运行时记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器一会对所有已经分配的内存进行跟踪监测,一旦发现有些内存已经不再使用,就会阶段性的回收这些没人用的内存。

更丰富的内置类型

除了几乎所有语言都支持的简单内置类型外,Go语言也内置了一些比较新的语言学中的内置的高级类型,比如C#和Java中的数组和字符串,除此之外,Go语言中还内置了一个对于其他静态类型语言通常用库支持的字典类型。另外又一个新增的数据结构,数组切片,我们可以认为数组切片是一种可动态增长的数组。

函数多返回值

目前主流语言中除了Python外基本都不支持函数的多返回值功能,比如我们如果要定义一个函数用于返回个人名字信息,而名字信息因为包含多个部分----姓名,中间名和别名,在不支持多返回值的语言中我们又以下两种做法,要么专门定义一个结构体用于返回,要么以传出参数的方式返回多个结构使用指针。
Go语言革命性的在静态语言阵营中率先提供了多返回值功能。Go语言中举例:

func getName()(firstName,middleName,lastName,nickName string){
     return "May","M","Chen","Babe"
}

因为返回值都已经有了名字,因此各个返回值也可以用如下方式来在不同的位置进行赋值,从而提供了极大的灵活性:

func getName()(firstName,middleName,lastName,nickName string){
    firstName = "May"
    middleName = "M"
    lastName = 'Chen'
    nickName = 'Babe'
}

并不是每一个返回值都必须赋值,没有明赋值的返回值将保留默认的空值,函数的调用也比较简单

fn,mn,ln,nn := getName()

如果我们只对函数其中的某几个返回值感兴趣的话。也可以直接用下划线作为占位符来忽略其他不关心的返回值。

_,_,lastName,_:=getName()

错误处理

Go语言引入了关键字defer用于标准的错误处理流程,并提供了内置函数panic,recover完成异常的抛出与捕获。

匿名函数和闭包

f := func(x,y int)int{
     return x+y
}

接口类型

Go语言的类型定义非常接近于C语言中的结构,甚至沿用了struct关键字。相比而言,Go语言并没有直接沿袭c++和JAVA的传统去设计一个超级复杂的类型系统,不支持继承和重载,而只是支持了最基本的类型组合功能。

Go语言并不是简单的对面向对象开发语言做减法,他还引入了一个无比强大的“非侵入式”接口的概念,在C++中,我们通常会这样来确定接口和类型的关系。

//抽象接口
interface IFly{
     virtual void Fly()=0;
};

//实现类
class Bird:public IFly{
     public:
          Bird(){}
          virtual ~Bird(){}
     public:
          void Fly(){
               //以鸟的方式飞行
}
};

void main(){
     IFly *pFly = new Bird();
     pFly ->Fly();
     delete pFly;
}

显然,在实现一个接口之前必须先定义该接口,并且将类型和接口紧密绑定,即接口的修改会影响到所有实现了该接口的类型。而Go语言的接口避免这类问题

type Bird struct{
     ...
}

func (b *Bird) Fly(){
     //以鸟的方式飞行
}

我们在实现Bird类型时完全没有任何IFLY的信息,我们可以在另一个地方定义这个IFly接口:

type IFly interface {
     Fly()
}

这两者目前看起来完全没有关系,现在看看我们怎么使用他们

func main(){
     var fly IFly = new(Bird)
     fly.Fly()
}

并发编程

Go语言引入了goroutine概念,他使得并发编程便得很简单,通过使用goroutine而不是裸用操作系统的并发机制,以及使用消息传递来共享内存而不是使用共享内存来进行通信。

通过在函数调用前使用关键字go,我们即可让该函数以goroutine方式执行,goroutime是一种比线程更加轻盈,更省资源的协程。Go语言通过系统的线程来多路派遣这些函数的执行,使得每个用go关键字执行的函数可以运行成为一个单位协程,当一个协程阻塞的时候,调度器就会自动把其他协程安排到另外的线程中去执行,从而实现了程序无等待并行化运行。而且调度的开销非常小。

Go语言实现了CSP(通信顺序进程)模型来作为goroutine间推荐通信方式。在CSP模型中,一个并发系统由若干并行运行的顺序进程组成,每个进程不能对其他进程的变量赋值。进程之间只能通过一对通信原语实现协作。Go语言用channel(通道)这个概念来轻巧地实现CSP模型,channel的使用方式比较接近Unix系统中的管道pipe概念,可以方便的进行跨goroutine的通信。

另外。由于一个进程内创建的所有goroutine运行在同一个地址内存空间,因此如果不同的goroutine不得不去访问共享的内存变量,访问前应该先获取相应的读写锁,Go语言标准库中的sync包提供了完备的读写锁功能。

一个简单的例子来演示goroutine和channel的使用方式,这是一个并行计算的例子,用两个goroutine进行并行的累加计算,待两个计算过程都完成后打印计算结果。

package main

import "fmt"

/*
这是一个并行计算的例子,由两个goroutine进行并行的累加计算
*/
func sum(values []int, resultChan chan int) {
    sum := 0
    for _, value := range values {
        sum += value
    }
    resultChan <- sum //将计算结果发送到channel中
}

func main() {
    values := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    resultChan := make(chan int, 2)
    go sum(values[:len(values)/2], resultChan)
    go sum(values[len(values)/2:], resultChan)
    sum1, sum2 := <-resultChan, <-resultChan //接收结果

    fmt.Println("Result:", sum1, sum2, sum2+sum1)
}

反射

通过反射,你可以获取对象类型的详细信息,并可动态操作对象。反射最常见的使用场景是做对象的序列化。

package main

/*
利用反射功能列出某个类型中所有成员变量的值
*/

import (
    "fmt"
    "reflect"
)

// 创建一个新类型
type Bird struct {
    Name           string
    LifeExpectance int
}

func (b *Bird) Fly() {
    fmt.Println("I'm flying")
}

func main() {
    sparrow := &Bird{"Sparrow", 3}
    s := reflect.ValueOf(sparrow).Elem()
    typeOfT := s.Type()
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d:%s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
    }
}

语言交互性

由于Go语言和C语言有天生联系,Go语言的设计者们自然不会忽略如何重用现有C模块的这个问题,这个功能直接被命名为Cgo,Cgo即是语言特性,同时也是一个工具的名称。

在Go语言中,可以按Cgo的特定语法混合编写C语言代码,然后Cgo工具可以将这些混合的C代码提取并生成对于C功能的调用包装代码。这里需要安装gcc编译环境

package main

/*
在Go语言中调用C语言标准库的puts函数

#include<stdio.h>
#include<stdlib.h>
*/

import (
    "C"
    "unsafe"
)

func main() {
    cstr := C.CString("Hello, world")
    C.puts(cstr)
    C.free(unsafe.Pointer(cstr))
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容