GO
支持goroutine 和通道,并且推荐使用消息而不是共享内存来进行并发编程,总体来说,Go语言是一个非常现代化的语言,精小但非常强大
Go语言的主要特性:
1、自动垃圾回收
2、更丰富的内置类型
3、函数多返回值
4、错误处理
5、匿名函数和闭包
6、类型和接口
7、并发编程
8、反射
9、语言交互性
Go语言的基础组成部分:
包声明
引入包
函数
变量
语句 &
表达式
注释
标识符(包括常量,变量,类型,函数名,结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的public
);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的protected)
go语言不能把大括号单独放一行,会错误
go
层序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号、如以下Go语句由6个标记组成
----标识符:用来命名变量、类型等程序实体、一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字
(0~9)
、下划线组成的序列,但是第一个子符必须是字母或下划线而不能是数字
----程序一般由关键字、变量、常量、运算符、类型和函数组成
程序中可能会使用到这些分割符:括号()
中括号[]
和大括号{}
程序中可能会使用到这些标点符号:
----go
语言中变量的声明必须使用空格隔开
go语言数据类型:在go编程语言中,数据类型用于声明函数和变量
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时侯需要用大数据的时侯才去申请大内存,就可以充分利用内存
go语言有以下数据类型:
1、bool
布尔类型的值可以是常量true
或者 flase
一个简单的例子 var
b bool = true
2、数字类型:整形
int
和浮点型 float64
,go语言支持整形和浮点型数字,并且原生支持复数,其中位运算采用补码
3、字符串类型:字符串就是一串固定长度的子符连接起来的子符序列,go的子符串是由单个字节连接起来的,go语言的字符串的字节使用UTF-8
编码标识unicode
文本
4、派生类型
包括:指针类型(Pointer)、数组类型、结构化类型(struct)、channel类型、函数类型、切片类型
接口类型(interface)、Map类型
----数字类型:
Go也有基于结构的类型,例如:int、uint、uintptr
go 语言变量
声明变量的一般形式是使用var
关键字:
var
indentifier (变量名)
type(类型)
值类型和引用类型
所有像int 、float 、 bool 和 string 这些基本类型都属于值类型,使用这些类型的变量直接指向存在在内存中的值:
当使用等号=将一个变量的值赋值给另一个变量时,如:j=i,实际上是在内存中将I 的值进行了拷贝:
你可以通过 &i
来获取变量 I
的内存地址,例如:0xf840000040
(每次的地址都可能不一样)。值类型的变量的值存储在栈中,内存地址会根据机器的不同而不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址,因为每台机器可能有不同的存储器布局,并且位置分配也可能不同
更复杂的数据通常会需要使用多个字节,这些数据一般使用引用类型保存
一个引用类型的变量
r1
存储的是 r1
的值所在的内存地址 (数字),或内存地址中第一个字所在的位置
这个内存地址为称之为指针,这个指针实际上也被存在另外的某一个字节中,同一个引用类型的指针指向的多个字节可以是在连续的内存地址中(内存布局是连续的)、这也是计算效率最高的一种存储形式;
也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址
这个内存地址称为指针,这个指针实际上也被存在另外的某一个字中
同一个引用类型的指针指向的多个字节可以是在连续的内存地址中(内存布局是连续的)、这也是计算效率最高的一种存储形式;
也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址
当使用赋值语句
r2
= r1 时,只有引用(地址)被复制
如果r1
的值被改变了,那么这个值的所有引用都会指向被修改后的内容,在这个例子中,r2
也会受到影响
简短形式,使用:=赋值操作符
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上var关键字其实是有些多余了,因此我们可以将它们简写为 a:= 50 或者 b:= false
a 和 b 的类型(int 和 bool) 将由编译器自动推断
这是使用变量的首选形式、但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值,使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明
注意事项:
如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如
:a
:= 20 就是不被允许的,编译器会提示错误no
new variables on left side of := 但是 a
= 20 是可以的,因为这是给相同的变量赋予一个新的值
如果你在定义变量a之前使用它,则会得到编译错误,undefinet
a
如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,例如下面这个例子当中的变量a
Go语言常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量
常量中的数据类型只可以是bool型,数字型,(整数型,浮点型和复数)和字符串型
常量的定义格式:
常量还可以用作枚举:
常量可以用len(),cap(),unsafe() 函数计算表达式的值,常量表达式中,函数必须是内置函数,否则编译不通过
位移
go 语言运算符
运算符用于在程序执行时执行数学或逻辑运算
Go语言内置的运算符有:
---算术运算符
+ - * / % ++ –
---关系运算符
== < > <= >=
---逻辑运算符
&& || !
---位运算符
& | ^ << >>
---赋值运算符
= += -= *= /= %= <<= >>= &= ^= |=
---其他运算符
& 返回变量存储地址
* 指针变量
运算符优先级:有些运算符有较高的优先级,二元运算符的运算方向均是从左至右,下表列出了所有运算符以及它们的优先级,由下至上代表优先级由高到低
Go语言条件语句
条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为true 来决定是否执行指定语句,并在条件为false 的情况再执行另外的语句
下图展示了程序语言中条件语句的结构:
go 语言提供了以下几种条件判断语句:
if语句 由一个布尔表达式后紧跟一个或多个语句组成、if。。。else 语句后可以使用可选的else语句,else语句中的表达式在布尔表达式值为false 时执行你可以在if 或 else if 语句中嵌入一个或多个 if 或 else if语句switch 语句用于基于不同条件执行不同动作select 语句类似于switch 语句,但是select 会随即执行一个可运行的case ,如果没有case 可运行,它将阻塞,直到有case 可运行
Go语言循环语句:
在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句
for 循环:重复执行语句块
循环嵌套:在for循环中嵌套一个或多个for循环
循环控制语句:
break语句:经常用于中断当前for循环或跳出switch语句
continue语句:跳过当前循环的剩余语句,然后继续进行下一轮循环
goto语句:将控制转移到被标记的语句
无限循环:如果循环中条件语句永远不为false
则会进行无限循环,我们可以通过
for
循环语句中只设置一个条件表达式来执行无限循环
Go语言函数
函数是基本的代码块,用于执行一个任务
Go语言最少有个main()
函数
你看以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务
函数声明告诉了编译器函数的名称,返回类型,和参数
Go语言标准提供了多种可动用的内置的函数,例如
len()
函数可以接受不同类型参数并返回该类型的长度,如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回的数组中包含的元素个数
Go 语言函数的定义格式如下:
func function_name ([paramter list]) [return_types]{………}
函数定义解析:
---func: 函数由 func 开始声明
---function_name : 函数名称,函数名和参数列表一起构成了函数签名
---parameter list :参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数,参数列表指定的是参数类型,顺序,及参数个数。参数是可选的,也就是说函数也可以不包含参数
---return_types : 返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下,return_types 不时必须的
---函数体:函数定义的代码集合
函数调用:当创建函数时,你定义了函数需要做什么,通过调用该函数来执行指定任务
函数调用,向函数传递参数,并返回值,例如:
函数返回多个值:
函数参数:
函数如果使用参数,该变量可称为参数的形参
形参就像定义在函数体内的局部变量
调用函数,可以通过两种方式来传递参数:
值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
默认情况下,Go语言使用的是值传递,即在调用过程中不会影响到实际参数
函数用法
函数作为值函数定义后可作为值来使用
闭包闭包就是匿名函数,可在动态编程中使用
方法方法就是一个包含了接受者的函数
Go语言变量作用域
作用域为已声明标识符所标识的常量、类型、变量、函数或包在源代码中的作用范围
Go语言中变量可以在三个地方声明:
---函数内定义的变量称为局部变量
---函数外定义的变量称为全局变量
---函数定义中的变量称为i形式参数
局部变量:在函数体内声明的变量称之为局部变量 ,它们的作用域只在函数体内,参数和返回值变量也是局部变量
全局变量:在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用全局辨两个可以在
任何函数中使用,
Go语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑
形式参数:形式参数会作为函数的局部变量来使用
初始化局部变量和全局变量
int 0
float32 0
pointer nil
Go语言数组
Go语言提供了数组类型的数据结构
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串
或者自定义类型、相对于去声明number0,number1....and number99 的变量,使用数组形式number[0],number[1]......
更加方便且易于扩展、数组元素可以通过索引(位值)来读取(或者修改)、索引从0开始、第一个元素索引为0,
第二个索引为1、以此类推
声明数组:
Go语言数组声明需要指定元素类型及元素个数,语法格式如下:
Go语言指针
Go语言中的指针是很容易学习的,Go语言中使用指针,可以更简单的执行一些任务,我们都知道变量是一种使用方便的
占位符,用于引用计算机内存地址,Go语言的取地址符是&,放到一个变量前使用就会相应变量的内存地址
什么是指针:一个指针变量指向了一个值的内存地址,类似于变量和常量,在使用指针前你需要声明指针
var var_name *var_type
变量 变量名 变量指针类型
使用指针:
---定义指针变量
---为指针变量赋值
---访问指针变量中指向地址的值
在指针类型前面加上 * 来获取指针所指向的内容
Go空指针
当一个被定义后没有分配到任何变量时,它的值为nil,nil 也称为空指针,nil 在概念上和其它语言的null,
None ,nil,NULL,一样,都代指零值或空值,一个指针变量通常缩写为ptr
Go语言结构体
Go语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型
结构体是一系列具有相同类型或不同类型的数据构成的数据集合
定义结构体:结构体定义需要使用 type 和 struct 语句、struct 定义一个新的数据类型,结构体中有一个或多个成员,
type 语句设定了结构体的名称、结构体的格式如下
访问结构体成员:如果要访问结构体成员,需要使用 "." 点号 操作符,格式为:
结构体.成员名
结构体作为函数参数:结构体可以像其它数据类型作为参数传递给函数
结构体指针:可以定义指向结构体的指针类似于其他指针变量
Go语言切片(Slice)
Go语言切片是对数组的抽象
Go数组的长度不可改变,在特定场景中这样的集合就不太适合,Go语言提供了一种灵活,功能强悍的内置类型切片(动态数组)、
与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大
定义切片:
可以声明一个未指定大小的数组来定义切片:
var identifile []type
切片不需要说明长度
使用make() 函数来创建切片
var slice1 []type = make([]type,len)
简写
slice1 := make([]type,len)
也可以指定容量,其中capacity 为可选参数
make([]T,length,capacity)
这里len 是数组的长度并且也是切片的长度
切片初始化
s := [] int{1,2,3}
直接初始化切片,[]表示是切片类型 ,{1,2,3} 初始化值依次是 1,2,3 其中cap = len = 3
s := arr[:]
初始化切片s是数组arr的引用
s := arr[startIndex:endIndex]
将arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片
s := arr[startIndex:]
缺省endIndex 时将表示一直到arr 的最后一个元素
s1 := s[startIndex:endIndex]
通过切片 s 初始化切片s1
s := make([]int,len,cap)
通过内置函数make() 初始化切片s, []int 标识为其元素类型为int 的切片
len() 和 cap() 函数
切片是可索引的,并且可以由len() 方法获取长度
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少
空(nil)切片:一个切片在未初始化之前默认为nil ,长度为0,
切片截取:可以通过设置上下限来设置截取切片
append() and copy() function
如果想要增加切片容量,我们必须创建一个新的更大的切片并把原分片的内容拷贝过来
下面的代码描述了从拷贝切片的copy 方法和向切片追加新元素的 append 方法
Go语言范围 (Range)
Go语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素
在数组和切片中它返回元素的索引和索引对应的值,在集合中返回key-value 对应的 key 值
Go语言Map(集合)
Map 是一种无序的键值对的集合,Map 最重要的一点是通过key 来快速检索数据,key 类似于索引,指向数据的值
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它,不过,Map是无序的,我们无法决定它的返回顺序
这是因为Map 是使用hash 表来实现的
定义Map:可以使用内建函数 make 也可以使用 map关键字来定义 Map:
/*声明变量,默认 map 是 nil*/
var map_variable map[key_data_type] value_data_type
/*使用 make 函数*/
map_variable := make(map[key_data_type] value_data_type)
如果不初始化 map, 那么就会创建一个 nil Map , nil map 不能用来存放键值对
delete() 函数
delet() 函数用于删除集合的元素,参数为map 和其对应的 Key
Go语言递归函数
递归:就是在运行的过程中调用自己
语法格式如下:
func recursion(){
recursion() /*函数调用自身*/
}
func main(){
recursion()
}
Go 语言支持递归,但我们在使用递归时,开发者需要设置退出条件,否则递归将进入无限循环中
递归对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等
阶乘:
斐波那契数列:
Go语言类型转换
类型转换用于将一种数据类型的变量转换为另外一种类型的变量,Go语言类型转换基本格式如下
type_name(expression)
type_nmae 为类型名,expression 为表达式
Go 语言接口
Go语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了
这些方法就是实现了这个接口
在上面的程序中,我们定义了一个接口Phone ,接口里面有一个方法 call() ,然后我们在 main() 函数里面定义了一个Phone类
型变量,并分别为之赋值为 NokiaPhone 和 Phone 然后调用 call() 方法
给接口增加参数:
Go 语言错误处理
Go语言通过内置的错误接口提供了非常简单的错误处理机制
error 类型是一个接口类型,这是它的定义:
type error interface {
Error() string
}
我们可以在编码中通过实现error 接口类型来生成错误信息
函数通常在最后的返回值中返回错误消息,使用error.New 可以返回一个错误信息:
func Sqrt(f float64) (float64,error) {
if f < 0 {
return 0,errors.New("math : square root of negative number")
}
}
在下面的例子中,我们在调用Sqrt 的时侯传递的一个复数,然后就得到了 non-nil 的 error 对象,将此对象与 nil 比较,结果为 true,
所以fmt.Println (fmt 包在处理 error 时会调用Error 方法)被调用,以输出错误
result,err := Sqrt(-1)
if err != nil{
fmt.Println(err)
}
实例:
至此基础的Go语言就算完成了,
IDE 可以用GoLand 个人感觉挺好用,可以装一下 vim 插件 vim 的操作习惯就不需要改变了