Go语言简明教程

muxxpkq · · 973 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/muxxpkq/article/details/53463071

Go语言简明教程


简介

创立时间

2007年 google作为20%项目开始研发
2009年11月10日 开源,获得TIOBE年度语言
2012年3月28日 发布Go1.0版本
2016年8月18日 发布Go1.7版本

创始人

Robert Griesemer (V8,Chubby,HotSpot JVM)
Rob Pike(Unix,UTF-8,plan9)
Ken Tompson(B语言、C语言、Unix之父,图灵奖)
lan Lance Taylor(GCC)
Brad Fitzpatrick(Memcache,HTTP2)

吉祥物

gopher:囊地鼠(产自北美的一种地鼠)
(https://github.com/golang/go/blob/master/doc/gopher/favicon.svg)

设计初衷

设计Go语言是为了解决当时Google内部开发的一些痛点
所处的环境:

  1. 大量的C++代码,同时又引入了Java和Python
  2. 成千上万的工程师(C系为主)
  3. 分布式的编译系统
  4. 数以百万记行的代码
  5. 数以万记的服务器

遇到的问题是:

  1. 新的C-like语言需求
  2. 语法繁杂、代码难以维护
  3. 失控的依赖
  4. 编译速度慢
  5. 交叉编译困难、难以部署

所以Go语言是一门工程上的实用主义语言

特点

  • C-like 语法风格
  • 强一致类型(静态语言)
  • struct组合复杂类型
  • function和Method
  • 没有异常处理(Error is value)
  • 基于首字母的访问控制
  • 多余的import和变量会引起编译错误
  • 内置GC
  • 完备的标准库包(网络编程、系统编程、互联网应用)
  • 支持各种编程范式:过程式编程、面向对象编程、函数式编程

语言要素

标识符

  • 代表一个变更或者一个类型,可以被看作是变量或者类型的代号或者名称
  • 若干字母、下划线(_)和数字组成的字符序列,第一个字符必须为字母
  • 在一个代码块中,不允许重复声明同一个标识
  • 预定义标识符
    • 所有基本数据类型的名称
    • 接口类型 error
    • 常量 true、false 以及 iota
    • 所有内置函数的名称,即 append、cap、close、complex、copy、delete、imag、len、make、new、panic、print、println、real和 recover

关键字

  • 又称保留字,不允许被使用为标识符
  • 25个关键字:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

- 程序声明:import、package
- 程序实体声明和定义:chan、const、func、interface、map、struct、type、var
- 程序流程控制:go、select、break、case、continue、default、defer、else、fallthrough、for、goto、if、range、return、switch

字面量

  • 表示值的一种标记法
  • 用于表示基础数据类型值的各种字面量
    • 数字 2016,1e9,1+2i
    • 字符串 “iota”
    • 布尔值 true,false
  • 用户构造各种自定义的复合数据类型的类型字面量
type Person struct {
    Name string
    Age uint8
    Address string
}
  • 用于表示复合数据类型的值的复合字面量
    • struct,array,slice,map构造的值
    • Person{Name: “Eric Pan”, Age: 28, Address: “Beijing China”}

操作符和分隔符

+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
// << /= <<= ++ = := , ;
% >> %= >>= ! . :
&^ &^=

优先级

优先级 操作符
5 * / % << >> & &^
4 + - | ^
3 == != < <= > >=
2 &&
1 ||

类型

  • 基本类型
    • bool
    • int/uint
    • int8/uint8/byte
    • int16/uint16
    • int32/uint32/rune
    • int64/uint64
    • float32/float64
    • complex64/complex128
    • string
  • 复杂类型
    • Array
    • Slice
    • Map
    • Struct
    • Interface
    • Function
    • Channel
    • Pointer
  • 潜在类型
    type MyString string //MyString是实际类型,string是潜在类型
  • 静态类型和动态类型
    除了interface都为静态类型,interface
    的动态性体现在运行时与该interface变量绑定在一起的值的实际类型

语法

变量/常量定义

    var v Type
    var v Type = value
    var v = value
    var v1,v2,v3 Type
    var v1,v2,v3 Type = value1,value2,value3
    var v1,v2,v3= value1,value2,value3
    v1,v2,v3:= value1,value2,value3
    i,j = j,i
//Tips::=为简短声明,编译器根据初始化的值自动推断相应的类型,但是不能定义在函数外部使用。
    const cname = value
    const cname type  = value
//Tips:声明但未使用的变量会在编译阶段报错。
    //声明分组
    import(
    “fmt”
    “os”
)
const(
    s = “string”
    pi = 3.1415
    pi2
)
var(
    i int
    pi float32 = 3.1415
)

iota枚举:为分组中iota++
const(
a = 1+iota*2
b
c = “iota”
d
)

array & slice

array定义

    var a [2]int = [2]int{1,2}  
    a := [2]int{1,2}    
    a := [...]int{1,2,3,4}
    a2 := [2][3]int{[3]int{1,2,3},[3]int{3,2,1}}    
    a2 := [2][3]int{{1,2,3},{3,2,1}}

slice定义

slice是引用类型

    var s []int  = make([]int,n)
    s := []int{v1,v2,v3}

slice操作

    copy(dst,src []Type)int //dst必须初始化完成,长度根据需要初始化
    append(slice []Type,elems ...Type)[]Type
    len(slice []Type)int
    cap(slice []Type)int

slice切片操作

    s[:j] == s[0:j]
    s[i:] == s[i:len(s)]
    s[i:j]:包含index区间为[i,j)s的元素
    //不能代替array和slice的copy操作,切片后是原数据的引用

map

引用类型,无序,长度不定,非线程安全

var m map[keyType]valueType //keyType可以是string及完全定义了==/!=操作的类型
m := make(map[keyType]valueType)
m:=map[keyType]valueType{k1:v1,k2:v2,k3:v3}
len(m map[keyType]valueType)int
delete(m map[Type]Type1,key Type)

channel

引用类型,goroutine之间通信的通道

    c := make(chan Type,n)//不初始化为nil
    c 

单向channel

    var c chan

channel操作

    close(ch)
    /*
关闭一个已关闭的channel会导致panic
向已关闭的channel中写数据会导致panic
从已关闭的channel中读数据不会导致panic   
v,ok := 

流程控制

if/else

    if x := getX();x > 0{
    //...
}else if x == 0{
    //...
}else{
    //...
}//依次逐条匹配,若匹配则进入逻辑块

switch/case

case e1:
    //...
case e2,e3:
    //...
    fallthrough
default:
    //...
}
//sExpr需要和case的expr类型一致,如果sExpr不存在,则比较类型为bool,只有true可以被匹配

for

for e1;e2;e3{
}
for expression{
}
//for + range 遍历slice和map数据

break:跳出当前循环,可以配合标签使用
continue:跳过本次循环,可以配合标签使用
for+range 遍历array/slice/map/string,循环接收channel中的数据

Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E

select

多channel的场景中,使用select机制,监听各个channel上的数据流动,默认阻塞,当监听的channel中有发送或可接收时才会工作,所有channel都准备好时,随机选择一个执行

    select{
        case c1

goto

func myFunc(){
    i := 0
Here:
    i++
    goto Here
}

函数

声明

    func funcName(input1 Type,input2 Type)([output1] Type,[output2] Type){
    return value1,value2
}

只有一个返回值且不声明返回变量,返回值的括号可以省略
没有返回值可以省略包括返回值的括号,且可以不需要return
如果有复数个相同Type的参数或返回值,可以省略重复Type声明,比如(a int,b int) =>(a,b int)
如果函数是导出的,建议命名返回值,提高可读性

变参

func funcName(arg ...Type){}
//arg为[]Type

支持多值返回

传值和传指针

使用指针类型传参
可以共同操作同一对象
传指针很轻量级,8B(64位机),对一些大的struct,在copy上会花费较多的系统开销

匿名函数和闭包

First-class value:可以作为别的函数的参数、返回值,可以赋值给变量,或者成为类型,函数式编程范式

func adder() func(int) int {
     sum := 0
     return func(x int) int {
          sum += x
          return sum
     }
}

特殊函数

defer函数
//在函数返回之前,先进后出执行defer语句,一般在需要资源回收的时候使用
main函数
func main(){
    //...
}
//package main中必须包含一个main函数,是程序的入口函数
init函数
func init(){
 //some init logic...
}
/*一个package中最好只写一个init
    1.如果package中需要import其他包,则先导入其他包
    2.所有包import完毕后,依次初始化cons->var->init()
*/

错误处理

panic

中断控制流程,之前入栈的defer函数依然会执行,然后返回到被调用的地方,调用方也认为触发了panic行为。依次向上,直到发生panic的goroutine上所有调用函数返回,导致程序退出
来源:调用panice,runtime error(数组越界,0值除数)

#

恢复panic,存在于defer函数中才有效

面向对象

struct

一种自定义用户类型
初始化

P := person{“iota”,22} //顺序初始化
P := person{age:22,name:”iota”} //field:value初始化
P := new(person) //new初始化

匿名字段
匿名字段可以是任意内置类型、struct、自定义类型
匿名字段命名冲突问题:最外层访问优先
Tag

method

  • 声明与函数的声明语法几乎一致,但是多了一个receiver部分,表示method依赖的主体
  • “A method is a function with an implicit first argument, called a receiver.”
  • receiver的值传递和引用传递,引用传递相当于OO语言中的this
  • 可以定义在包括struct在内的任何自定义类型(c中的typedef)、内置类型
  • 无论receiver是指针还是值,go都会自动相互转换
  • 继承method后可以重写method
  • 通过声明开头的大小来表明是否可以导出

interface

  • 一组method签名的组合
  • 如果某个struct实现了某个接口的所有方法,则- 此对象就实现了此接口
  • Any类型:interface{} like void*
  • interface{}的类型转换:
    断言:value,ok = element.(T)
    switch:T := element.(type),这种语法只能在switch代码块中使用,default表示的意义
  • embedded interface
    type ReadWriter interface{
    Reader
    Writer
    }

package

  • package相当于python中的module
  • 大写字母开头的变量和函数是可导出的,是public的
  • 小写字母开头的变量和函数是不可导出的,是private的
  • import:导入package的方式
    类似树结构的深度优先遍历
    若包已加载,则跳过
    包的初始化顺序:const、var、init()
    依次从GOROOT、GOPATH(可能有多个)寻找目标package
    点import:使用包的导出资源时,可以省略包名
    别名import
    预加载import:不引入包,只是调用该包的init(),比如数据库驱动的加载
  • 禁止循环导入,禁止导入包未使用

面向对象特性

  • 封装、继承、多态
  • 类的定义
  • interface:动态绑定
  • Any类型:interface{}
  • 包管理:public、private、import

reflect

  • 检查程序在runtime的状态
  • reflect.Type 类型定义: reflect.TypeOf(v)
    t.Elem().Field(0).Tag
  • reflect.Value 存储的值: reflect.ValueOf(v)
    v.Elem().Field(0).String()
  • Kind():潜在类型的实际类型
  • 若要改变原始变量的值,需要反射变量的指针
    var x float64 = 3.4
    p := reflect.ValueOf(&x)
    v := p.Elem()
    v.SetFloat(7.1)

并发模型

  • Goroutine:协程、轻量级、底层混合使用nonblockingIO和线程、极小栈内存
  • Channel:功能(传值&同步)读写阻塞
  • Select:同时监听多个channel
  • CSP(Communicating sequential processes)通信顺序进程
  • 通过通信来共享、而不是通过共享来通信

runtime

  • Goexit:退出当前goroutine,但是defer正常执行
  • Gosched:让出当前goroutine的执行权限,调度器安排其他goroutine执行,并在下次某个时候从该位置恢复执行
  • NumCPU:返回CPU数量
  • NumGoroutine:返回正在执行和排队的任务总数
  • GOMAXPROCS:设置并行计算的最大CPU核数,并返回之前设置的值

开发环境

版本

1.7 截止2016/12

安装方式

可执行文件安装
源码安装

path

GOROOT
GOPATH

IDE

  • LiteIDE
  • VSCode
  • Sublime Text (Go plugin by offical)
    DEBUG
  • gdb
  • delve
  • log

go命令

  • go build
  • go clean
  • go run
  • go install
  • go get
  • go tool
  • go doc
  • go env
  • go version

常用类库

  • 运行时:runtime,runtime/debug,runtime/pprof,runtime/cgo
  • 系统库:os
  • 网络库:net,net/http,net/rpc
  • io操作:io、io/ioutil,
  • 编码库:json,base64,xml
  • 压缩库:gzip
  • 加密库:MD5,SHA-1,SHA-256,aes,des,rsa
  • 同步:sync,sync/atomic
  • 数据库:database/sql

语言对比

C/C++

  • 上限高:速度更快、内存利用率高
  • 下限低:内存泄漏、core dump
  • 语言层级没有对并发支持、调用os的并发机制(线程、进程)

Java

  • 语言繁琐
  • 语言层级的线程并发支持
  • 开发效率低

PHP/PYTHON/RUBY

  • 开发效率快,但是差距不大
  • 运行速度慢
  • 语言层级裸用os的并发机制

应用场景

  • 服务中间件
    日志、文件系统
  • 分布式系统、数据库代理器
  • 网络编程
    web应用、api应用、下载应用
  • 数据库
    Groupcache(Google) Couchbase Tidb Cockrouchdb Influxdb
  • 云平台
    CloudFoundy Apcera DaoCloud 七牛云

优势

  • 学习曲线平滑
  • 容易写出健壮、稳定、高性能的程序
  • 开发效率高(近PHP的开发效率)
  • 运行性能好(近C的运行效率)
  • 语言层级多核并发支持,且简单易用
  • 二进制文件、Copy部署
  • 运行快、开发快、部署快

有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:muxxpkq

查看原文:Go语言简明教程

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

973 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传