go语言 - 初次见面

语言特性

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

自动垃圾回收

编程中,一个难题就是内存管理,如果管理不好对内存的使用,发生内存泄露可能会引发严重的问题,比如使程序崩溃。C和C++这样的编程语言,提供了指针这样灵活的类型,但却必须手动管理内存,增加了编程的复杂性。Java等编程语言本身提供了自动的垃圾回收机制,减少了编程的不少负担。go语言融合了众多编程语言的优秀特点,自然也引入了自动的垃圾回收机制。

所谓垃圾回收,即所有的内存分配动作都会被在运行时记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器会对所有已经分配的内存进行跟踪监测,一旦发现有些内存已经不再被任何人使用,就阶段性地回收这些没人用的内存。当然,因为需要尽量最小化垃圾回收的性能损耗,以及降低对正常程序执行过程的影响,现实中的垃圾回收算法要比这个复杂得多,比如为对象增加年龄属性等,但基本原理都是如此。

更丰富的内置类型

go语言不仅提供了几乎所有语言都提供的整形,浮点型等简单类型,数组和字符串等高级类型,还提供了字典类型(map),数组切片(Slice)。

函数多返回值

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"
    return
}

并不是每一个返回值都必须赋值,没有被明确赋值的返回值将保持默认的空值。
多返回值函数调用:

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

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

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

错误处理

Go语言引入了3个关键字用于标准的错误处理流程。

  • defer
  • panic
  • recover

与C++和Java等语言中的异常捕获机制相比, Go语言的错误处理机制可以大量减少代码量,让开发者也无需仅仅为了程序安全性而添加大量一层套一层的try-catch语句。
代码中过多的嵌套,真是让人抓狂。

匿名函数和闭包

在Go语言中,所有的函数也是值类型,可以作为参数传递。

类型和接口

Go语言不支持继承和重载,而只是支持了最基本的类型组合功能。
Go语言引入了一个无比强大的“非侵入式” 接口的概念,让开发者从以往对C++和Java开发中的接口管理问题中解脱出来。

go语言简单的接口使用示例:

type Bird struct {
    ...
}

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

}

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

type IFly interface { 
    Fly()
}

上面两个定义看起来丝毫没有关系,现在看看如何使用它们:

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

可以看出,虽然Bird类型实现的时候,没有声明与接口IFly的关系,但接口和类型可以直接转换,甚至接口的定义都不用在类型定义之前,这种比较松散的对应关系可以大幅降低因为接口调整而导致的大量代码调整工作。

并发编程

Go语言引入了goroutine概念,它使得并发编程变得非常简单。通过使用goroutine而不是裸用操作系统的并发机制,以及使用消息传递而不是共享内存来通信,Go语言让并发编程变得更加轻盈和安全。

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

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

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

反射

Go语言的反射实现了反射的大部分功能,但没有像Java语言那样内置类型工厂,所以无法做到像Java那样通过类型字符串创建对象实例。

反射最常见的使用场景是做对象的序列化(serialization)。 例如,Go语言标准库的encoding/json、encoding/xml、encoding/gob、encoding/binary等包就大量依赖于反射功能来实现。

go语言发射的简单示例:

package main

import (
    "fmt"
    "reflect"
)

type Bird struct {
    Name           string
    LifeExpectance int
}

func (b *Bird) Fly() {
    fmt.Println("I am 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())
    }
}

输出结果:
0: Name string = Sparrow
1: LifeExpectance int = 3

语言交互性

Go语言为了方便的重用现有的C模块,提供了Cgo。
在Go代码中,可以按Cgo的特定语法混合编写C语言代码,然后Cgo工具可以将这些混合的C代码提取并生成对于C功能的调用包装代码。

Go语言使用C模块的简单示例:

package main
/*
#include <stdio.h> 
*/
import "C"
import "unsafe"
func main() {
    cstr := C.CString("Hello, world") 
    C.puts(cstr) 
    C.free(unsafe.Pointer(cstr))
}

语言结构

基础组成

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释

简单示例

学习一门语言,从输出“Hello,world!”开始。

package main

import "fmt"

func main() {
   fmt.Println("Hello, World!")/* 输出Hello, World! */
}
  • package main定义了包名。必须在源文件中非注释的第一行指明这个文件属于哪个包。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
  • import "fmt" 告诉 Go 编译器这个程序需要使用fmt包中的内容。
  • func main() 是程序开始执行的函数。main函数是每一个可执行程序所必须包含的。
  • /*...*/ 是多行注释。你也可以使用单行注释//
  • fmt.Println("Hello, World!"),使用fmt包中的输出函数Println将“Hello, World!”字符串输出到控制台。

执行go程序

  1. 在你的机器上,安装go语言开发环境。
  2. 在你设置的工作目录下,新建hello.go文件。
  3. 将上面示例代码复制到hello.go文件中。
  4. 进入hello.go所在目录,执行go run hello.go命令行
$ go run hello.go
Hello, World!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容