Loading

golang基础

什么是Go

 

Go是一门 并发支持 、垃圾回收 的 编译型 系统编程语言,旨在创

造一门具有在静态编译语言的 高性能 和动态语言的 高效开发 之间拥有

良好平衡点的一门编程语言。

 

Go的主要特点有哪些?

 

类型安全 内存安全

以非常直观和极低代价的方案实现 高并发

高效的垃圾回收机制

快速编译(同时解决C语言中头文件太多的问题)

为多核计算机提供性能提升的方案

UTF-8编码支持

 

 

Go环境变量与工作目录

 

根据约定,GOPATH下需要建立3个目录:

bin(存放编译后生成的可执行文件)

pkg(存放编译后生成的包文件)

src(存放项目源码)

 

 

Go命令

 

        在命令行或终端输入go即可查看所有支持的命令

 

Go常用命令简介

 

go get:获取远程包(需 提前安装 githg

go run:直接运行程序

go build:测试编译,检查是否有编译错误

go fmt:格式化源码(部分IDE在保存时自动调用)

go install:编译包文件并编译整个程序

go test:运行测试文件

go doc:查看文档(CHM手册)

 

 

 

 

Go内置关键字(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

 

 

Go注释方法

 

// :单行注释

/* */:多行注释

 

 

Go程序的一般结构:basic_structure.go

 

 

 

Go程序是通过 package 来组织的(与python类似)

 

只有 package 名称为 main 的包可以包含 main 函数

 

一个可执行程序 有且仅有 一个 main

 

 

 

通过 import 关键字来导入其它非 main

 

通过 const 关键字来进行常量的定义

 

通过在函数体外部使用 var 关键字来进行全局变量的声明与赋值

 

通过 type 关键字来进行结构(struct)或接口(interface)的声明

 

通过 func 关键字来进行函数的声明

 

 

Go基本类型

 

 

 

布尔型:bool

 

- 长度:1字节

 

- 取值范围:true, false

 

- 注意事项:不可以用数字代表truefalse

 

 

 

整型:int/uint

 

- 根据运行平台可能为3264

 

 

 

8位整型:int8/uint8

 

- 长度:1字节

 

- 取值范围:-128~127/0~255

 

字节型:byteuint8别名)

 

 

16位整型:int16/uint16

 

- 长度:2字节

 

- 取值范围:-32768~32767/0~65535

 

32位整型:int32rune/uint32

 

- 长度:4字节

 

- 取值范围:-2^32/2~2^32/2-1/0~2^32-1

 

64位整型:int64/uint64

 

- 长度:8字节

 

- 取值范围:-2^64/2~2^64/2-1/0~2^64-1

 

浮点型:float32/float64

 

- 长度:4/8字节

 

- 小数位:精确到7/15小数位

 

 

复数:complex64/complex128

 

- 长度:8/16字节

 

足够保存指针的 32 位或 64 位整数型:uintptr

 

 

 

其它值类型:

 

- arraystructstring

 

引用类型:

 

- slicemapchan

 

 

 

接口类型:inteface

 

函数类型:func

 

类型零值

 

        零值并不等于空值,而是当变量被声明为某种类型后的默认值,

通常情况下值类型的默认值为0boolfalsestring为空字符串

 

 

单个变量的声明与赋值

 

 

 

变量的声明格式:var <变量名称> <变量类型>

 

变量的赋值格式:<变量名称> = <表达式>

 

声明的同时赋值:var <变量名称> [变量类型] = <表达式>

 

 

 

多个变量的声明与赋值

 

全局变量的声明可使用 var() 的方式进行简写

全局变量的声明不可以省略 var,但可使用并行方式

所有变量都可以使用类型推断

局部变量不可以使用 var() 的方式简写,只能使用并行方式

 

 

 

 

 

 

变量的类型转换

 

Go中不存在隐式转换,所有类型转换必须显式声明

转换只能发生在两种相互兼容的类型之间

类型转换的格式:

<ValueA> [:]= <TypeOfValueA>(<ValueB>)

 

 

 

常量的定义

 

常量的值在编译时就已经确定

常量的定义格式与变量基本相同

等号右侧必须是常量或者常量表达式

常量表达式中的函数必须是内置函数

 

 

 

 

常量的初始化规则与枚举

 

在定义常量组时,如果不提供初始值,则表示将使用上行的表达式

使用相同的表达式不代表具有相同的值

iota是常量的计数器,从0开始,组中每定义1个常量自动递增1

通过初始化规则与iota可以达到枚举的效果

每遇到一个const关键字,iota就会重置为0

 

 

 

 

 

 

 

 

运算符

 

 

 

Go中的运算符均是从左至右结合

 

 

 

优先级(从高到低)

 

 

 

^      !                                               (一元运算符)

 

*       /    %    <<    >>    &      &^

 

+      -     |      ^                                (二元运算符)

 

==   !=   <    <=    >=    >

 

<-                                              (专门用于channel

 

&&

 

||

 

指针

 

        Go虽然保留了指针,但与其它编程语言不同的是,在Go当中不

支持指针运算以及->”运算符,而直接采用”.”选择符来操作指针

目标对象的成员

 

操作符&”取变量地址,使用”*”通过指针间接访问目标对象

默认值为 nil 而非 NULL

 

 

递增递减语句

 

        Go当中,++ -- 是作为语句而并不是作为表达式

 

 

判断语句if

 

 

 

条件表达式没有括号

 

支持一个初始化表达式(可以是并行方式)

 

左大括号必须和条件语句或else在同一行

 

支持单行模式

 

初始化语句中的变量为block级别,同时隐藏外部同名变量

 

1.0.3版本中的编译器BUG

 

 

 

 

循环语句for

 

Go只有for一个循环语句关键字,但支持3种形式

初始化和步进表达式可以是多个值

条件语句每次循环都会被重新检查,因此不建议在条件语句中

使用函数,尽量提前计算好条件并以变量或常量代替

左大括号必须和条件语句在同一行

 

选择语句switch

 

可以使用任何类型或表达式作为条件语句

不需要写break,一旦条件符合自动终止

如希望继续执行下一个case,需使用fallthrough语句

支持一个初始化表达式(可以是并行方式),右侧需跟分号

左大括号必须和条件语句在同一行

 

 

跳转语句goto, break, continue

 

三个语法都可以配合标签使用

标签名区分大小写,若不使用会造成编译错误

Breakcontinue配合标签可用于多层循环的跳出

Goto是调整执行位置,与其它2个语句配合标签的结果并不相同

 

 

 

数组Array

 

 

 

定义数组的格式:var <varName> [n]<type>n>=0

 

数组长度也是类型的一部分,因此具有不同长度的数组为不同类型

 

注意区分指向数组的指针和指针数组

 

数组在Go中为值类型

 

数组之间可以使用==!=进行比较,但不可以使用<>

 

可以使用new来创建数组,此方法返回一个指向数组的指针

 

Go支持多维数组

 

 

 

 

切片Slice

 

 

 

其本身并不是数组,它指向底层的数组

 

作为变长数组的替代方案,可以关联底层数组的局部或全部

 

为引用类型

 

可以直接创建或从底层数组获取生成

 

使用len()获取元素个数,cap()获取容量

 

一般使用make()创建

 

如果多个slice指向相同底层数组,其中一个的值改变会影响全部

 

 

 

make([]T, len, cap)

 

其中cap可以省略,则和len的值相同

 

len表示存数的元素个数,cap表示容量

 

 

 

Reslice

 

Reslice时索引以被slice的切片为准

索引不可以超过被slice的切片的容量cap()

索引越界不会导致底层数组的重新分配而是引发错误

 

Append

可以在slice尾部追加元素

可以将一个slice追加在另一个slice尾部

如果最终长度未超过追加到slice的容量则返回原始slice

如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据

 

 

 

map

 

 

 

类似其它语言中的哈希表或者字典,以key-value形式存储数据

 

Key必须是支持==!=比较运算的类型,不可以是函数、mapslice

 

Map查找比线性搜索快很多,但比使用索引访问数据的类型慢100

 

Map使用make()创建,支持 := 这种简写方式

 

 

 

make([keyType]valueType, cap)cap表示容量,可省略

 

超出容量时会自动扩容,但尽量提供一个合理的初始值

 

使用len()获取元素个数

 

 

 

键值对不存在时自动添加,使用delete()删除某键值对

 

使用 for range mapslice进行迭代操作

 

 

 

 

 

函数function

 

 

 

Go 函数 不支持 嵌套、重载和默认参数

 

但支持以下特性:

 

 

 

        无需声明原型、不定长度变参、多返回值、命名返回值参数

 

        匿名函数、闭包

 

 

 

定义函数使用关键字 func,且左大括号不能另起一行

 

函数也可以作为一种类型使用

 

 

defer

 

的执行方式类似其它语言中的析构函数,在函数体执行结束后

按照调用顺序的相反顺序逐个执行

即使函数发生严重错误也会执行

支持匿名函数的调用

常用于资源清理、文件关闭、解锁以及记录时间等操作

通过与匿名函数配合可在return之后修改函数计算结果

如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer

时即已经获得了拷贝,否则则是引用某个变量的地址

 

Go 没有异常机制,但有 panic/recover 模式来处理错误

Panic 可以在任何地方引发,但recover只有在defer调用的函数中有效

 

 

 

结构struct

 

 

 

Go 中的structC中的struct非常相似,并且Go没有class

 

使用 type <Name> struct{} 定义结构,名称遵循可见性规则

 

支持指向自身的指针类型成员

 

支持匿名结构,可用作成员或定义成员变量

 

匿名结构也可以用于map的值

 

可以使用字面值对结构进行初始化

 

允许直接通过指针来读写结构成员

 

相同类型的成员可进行直接拷贝赋值

 

支持 == !=比较运算符,但不支持 > <

 

支持匿名字段,本质上是定义了以某个类型名为名称的字段

 

嵌入结构作为匿名字段看起来像继承,但不是继承

 

可以使用匿名字段指针

 

 

方法method

 

Go 中虽没有class,但依旧有method

通过显示说明receiver来实现与某个类型的组合

只能为同一个包中的类型定义方法

Receiver 可以是类型的值或者指针

不存在方法重载

可以使用值或指针来调用方法,编译器会自动完成转换

从某种意义上来说,方法是函数的语法糖,因为receiver其实就是

方法所接收的第1个参数(Method Value vs. Method Expression

如果外部结构和嵌入结构存在同名方法,则优先调用外部结构的方法

类型别名不会拥有底层类型所附带的方法

方法可以调用结构中的非公开字段

 

接口interface

 

接口是一个或多个方法签名的集合

只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示

声明实现了哪个接口,这称为 Structural Typing

接口只有方法声明,没有实现,没有数据字段

接口可以匿名嵌入其它接口,或嵌入到结构中

将对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个

复制品的指针,既无法修改复制品的状态,也无法获取指针

只有当接口存储的类型和对象都为nil时,接口才等于nil

接口调用不会做receiver的自动转换

接口同样支持匿名字段方法

接口也可实现类似OOP中的多态

空接口可以作为任何类型数据的容器

 

类型断言

 

通过类型断言的ok pattern可以判断接口中的数据类型

使用type switch则可针对空接口进行比较全面的类型判断

 

接口转换

 

可以将拥有超集的接口转换为子集的接口

 

反射reflection

 

反射可大大提高程序的灵活性,使得 interface{} 有更大的发挥余地

反射使用 TypeOf ValueOf 函数从接口中获取目标对象信息

反射会将匿名字段作为独立字段(匿名字段本质)

想要利用反射修改对象状态,前提是 interface.data settable

pointer-interface

- 通过反射可以“动态”调用方法

 

 

并发concurrency

 

 

 

很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从

 

源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已。

 

不过话说回来,每个实例 4-5KB 的栈内存占用和由于实现机制而大幅

 

减少的创建和销毁开销,是制造 Go 号称的高并发的根本原因。另外,

 

goroutine 的简单易用,也在语言层面上给予了开发者巨大的便利。

 

 

 

并发不是并行:Concurrency Is Not Parallelism

 

并发主要由切换时间片来实现“同时”运行,在并行则是直接利用

 

多核实现多线程的运行,但 Go 可以设置使用核数,以发挥多核计算机

 

的能力。

 

 

 

Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。

 

 

 

Channel

 

 

 

Channel goroutine 沟通的桥梁,大都是阻塞同步的

 

通过 make 创建,close 关闭

 

Channel 是引用类型

 

可以使用 for range 来迭代不断操作 channel

 

可以设置单向或双向通道

 

可以设置缓存大小,在未被填满前不会发生阻塞

 

 

 

Select

 

 

 

可处理一个或多个 channel 的发送与接收

 

同时有多个可用的 channel时按随机顺序处理

 

可用空的 select 来阻塞 main 函数

 

可设置超时

 

posted @ 2020-03-18 11:13  Devops、小铁匠  阅读(323)  评论(0)    收藏  举报