Go语言中的标识符必须以字母(Unicode字母,PHP/JS能够用中文做为变量名)下划线开头。大写字母跟小写字母是不一样的:Hello和hello是两个不一样的名字。
Go中有25个关键字:golang
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
若是一个名字是在函数内容定义,那么它的做用域就在函数内容,若是在函数外部定义,那么将在当前包的全部文件中均可以访问。名字的开头字母的大小写决定了名字在包外的可见性。若是一个名字是大写字母开头,那么它能够被外部的包访问,例如fmt包的Printf函数。数组
// 当前程序的包名 package main // 导入其余的包 import "fmt" // 一次导入多个包 import ( "io" "os" ) // 常量的定义 const PI = 3.14 // 全局变量的声明与赋值,该变量在整个package中使用 var name = "go" // 通常类型声明 type newType int // 结构的声明 type go struct{} // 接口的声明 type golang interface{} // 由main函数做为程序入口启动 func main() { fmt.Println("Hello World!") }
Go语言中使用大小写来决定该常量、变量、类型、接口、结构或函数是否能够被外部包所调用: 根据约定,函数名首字母小写即为private(外部不能够调用),大写为public缓存
// var 变量名称 变量类型 = 值 var num int = 1
var num1,num2 int = 1, 2
var (
num1 int = 1 num2 int = 2 )
Go的整数类型一共有10个
其中计算架构相关的整数类型有两个: 有符号的整数类型 int, 无符号的整数类型 uint。
在不一样计算架构的计算机上,它们体现的宽度(存储某个类型的值所须要的空间)是不同的。空间的单位能够是bit也能够是字节byte。
安全
除了这两个计算架构相关的整数类型以外,还有8个能够显式表达自身宽度的整数类型:
数据结构
若是以8进制为变量num赋值:架构
num = 039 // 用"0"做为前缀以代表这是8进制表示法
若是以16进制为变量num赋值:并发
num = 0x39
浮点数类型有两个:float32/float64 浮点数类型的值通常由整数部分、小数点"."和小数部分组成。另一种表示方法是在其中加入指数部分。指数部分由"E"或"e"以及带正负号的10进制整数表示。例:3.9E-2表示浮点数0.039。3.9E+1表示浮点数39。
有时候浮点数类型值也能够被简化。好比39.0能够被简化为39。0.039能够被简化为.039。 在Go中浮点数的相关部分只能由10进制表示法表示。app
复数类型有两个:complex64和complex128。实际上,complex64类型的值会由两个float32类型的值分别表示复数的实数部分和虚数部分。而complex128类型的值会由两个float64类型的值表示复数的实数部分和虚数部分。
负数类型的值通常由浮点数表示的实数部分、加号"+"、浮点数表示的虚数部分以及小写字母"i"组成,好比3.9E+1 + 9.99E-2i。函数
byte与rune都属于别名类型。byte是uint8的别名类型,而rune是int32的别名类型。
一个rune的类型值便可表示一个Unicode字符。一个Unicode代码点一般由"U+"和一个以十六进制表示法表示的整数表示,例如英文字母'A'的Unicode代码点为"U+0041"。
rune类型的值须要由单引号"'"包裹,不过咱们还能够用另外几种方式表示: ui
另外在rune类型值的表示中支持几种特殊的字符序列,即:转义符。以下图:
字符串的表示法有两种,即:原生表示法和解释型表示法。原生表示法,需用用反引号"`"把字符序列包起来,若是用解释型表示法,则须要用双引号"""包裹字符序列。
var str1 string = "str" var str1 string = `str`
两者的区别是,前者表示的是所见即所得的(除了回车符)。后者所表示的值中转义符会起做用。字符串值是不可变的,若是咱们建立了一个此类型的值,就不可能再对它自己作任何修改。
一个数组是能够容纳若干相同类型的元素的容器。数组的长度是固定的。以下声明一个数组类型:
type MyNumbers [3]int
类型声明语句由关键字type、类型名称和类型字面量组成
上面这条类型声明语句其实是为数组类型[3]int声明了一个别名类型。这使得咱们能够把MyNumbers看成数组类型[3]int来使用。
咱们表示这样一个数组类型的值的时候。应该把该类型的类型字面量写在最左边,而后用花括号包裹该值包含的若干元素,各元素之间以(英文半角)逗号分割,即:
[3]int{1,2,3}
如今咱们把这个数组字面量赋给一个名为numbers的变量:
var numbers = [3]int{1,2,3}
这是一条变量声明语句,它在声明变量的同时为该变量赋值
另外一种方式是在其中的类型字面量中省略表明其长度的数组,例:
var numbers = [...]int{1,2,3}
能够用以下方式访问该变量中的任何一个元素。例:
numbers[0] numbers[1] numbers[2]
若是要修改数组值中的某一个元素值,能够:
numbers[1] = 4
能够用以下方式获取数组长度:
var length = len(numbers)
若是一个数组没有赋值,则它的默认值为[length]type{0,0,0...}
切片(slice)与数组同样也是能够若干相同类型元素的容器。与数组不一样的是切片类型的长度不肯定。每一个切片值都会将数组做为其底层数据结构。表示切片类型的字面量如:
[]int
或者是:
[]string
切片类型的声明能够这样:
type MySlice []int
对切片值的表示也与数组值类似
[]int{1,2,3}
操做数组值的方法一样适用于切片值。还有一种操做数组的方式叫作“切片”,实施切片操做的方式就是切片表达式。例:
var number3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4]
上例中切片表达式numbers3[1:4]的结果为[]int{2,3,4}很明显被切下的部分不包含元素上界索引指向的元素。实际上slice1这个切片值的底层数组正是number3的值。
咱们也能够在切片值上实施切片操做:
var slice2 = slice1[1:3]
除了长度切片值以及数组值还有另一个属性--容量。数组的容量老是等于其长度,而切片值的容量每每与其长度不一样。以下图:
如图所示,一个切片值的容量即为它的第一个元素值在其底层数组中的索引值与该数组长度的差值的绝对值。可使用cap()内建函数获取数组、切片、通道类型的值的容量:
var capacity2 int = cap(slice2)
切片类型属于引用类型,它的零值即为nil,即空值。若是咱们只声明了一个切片类型而不为它赋值,则它的默认值:nil。
有些时候咱们能够在方括号中放入第三个正整数。以下图所示:
numbers3[1:4:4]
第三个正整数为容量上界索引,它意义在于能够把做为结果的切片值的容量设置的更小。它能够限制咱们经过这个切片值对其底层数组中的更多元素的访问。上节中numbers3和slice的赋值语句以下:
var numbers3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4]
这时,变量slice1的值是[]int{2,3,4}。可是咱们能够经过以下操做将其长度延展与其容量相同:
slice1 = slice1[:cap(slice1)]
经过此操做,变量slice1的值变为了[]int{2,3,4,5},且其长度和容量均为4。如今number3的值中的索引值在(1,5)范围内的元素都被体如今了slice1的值中。这是以number3的值是slice1的值的底层数组为前提的。这意味着咱们能够垂手可得地经过切片访问其底层数组中对应索引值更大的更多元素。若是咱们编写的函数返回了这样一个切片值,那么获得它的程序极可能会经过这种技巧访问到本不该该暴露给它的元素。
若是咱们在切片中加入了第三个索引(即容量上限索引),如:
var slice1 = numbers3[1:4:4]
那么在此以后,咱们将没法经过slice1访问到number3的值中的第五个元素。
虽然切片值在上述方面受到了其容量的限制。可是咱们能够经过另一种手段对其进行不受限制的扩展。这须要用到内建函数append。append会对切片值进行扩展并返回一个新的切片值,使用方法以下:
slice1 = append(slice1, 6, 7)
经过上述操做,slice1的值变为了[]int{2,3,4,6,7}。一旦扩展操做超出了被操做的切片值的容量,那么该切片的底层数组就会被替换 最后一种操做切片的方式是“复制”。该操做的实施方法是调用copy函数。该函数接收两个类型相同的切片值做为参数,并把第二个参数值中的元素复制到第一个参数值中的相应位置(索引值相同)上。这里有两点须要注意:
例:
var slice4 = []int{0,0,0,0,0,0} copy(slice4, slice1)
经过上述复制操做,slice4会变成[]int{2,3,4,6,7,0,0}。
Go语言的字典(Map)类型是一个哈希表的实现。字典类型的字面量以下:
map[K]T
其中,"K"为键的类型,而"T"则表明元素(值)的类型。若是咱们描述一个键类型为int,值类型为string的字典类型的话:
map[int]string
字典的键类型必须是可比较的,不然会引发错误,即键不能是切片、字典、函数类型
字典值的字面量表示法实际上与数组的切片的字面量表示法很类似。最左边仍然是类型字面量,右边紧挨着由花括号包裹且有英文逗号分隔的键值对。每一个键值对的键和值之间由冒号分隔。以字典类型map[int]string为例。他的值的字面量能够是这样的:
map[int]string{1:"a",2:"b"m,3:"c"}
咱们能够把这个值赋给一个变量
mm := map[int]string{1:"a",2:"b",3:"c"}
可用索引表达式取出字典中的值:
b := mm[2]
能够用索引表达式赋值:
mm[2] = b + "2"
这样mm中键为2的值变为了"b2"。能够用以下方式向字典中添加一个键值对:
mm[4] = ""
对于字典值来讲,若是指定键没有对应的值则默认为该类型的空值。因此mm[5]会返回一个""。可是这样的话咱们就不知道mm[5]究竟是""仍是mm[5]没有这个值。因此go提供了另一种写法:
e, ok := mm[5]
针对字典的索引表达式能够有两个求职结果,第二个求职结果是bool类型的。它用于代表字典值中是否存在指定的键值对。 从字典中删除键值对的方法很是简单,仅仅是调用内建函数delete:
delete(mm, 4)
不管mm中是否存在以4为键的键值对,delete都删除。 字典类型属于引用类型,它的零值即为nil
通道(Channel)是Go语言中一种很是独特的数据结构。它可用于在不一样Goroutine之间传递类型化的数据。而且是并发安全的。相比之下,以前几种数据类型都不是并发安全的。
Goroutine能够被看做是承载可被并发执行的代码块的载体。它们由Go语言的运行时系统调度,并依托操做系统线程(又称内核线程)来并发地执行其中的代码块。
通道类型的表示方法很简单,仅由两部分组成:
chan T
在这个类型字面量中,左边是表明通道类型的关键字chan,而右边则是一个可变的部分,即表明该通道类型容许传递的数据的类型(或称通道的元素类型)。
与其余的数据类型不一样,咱们没法表示一个通道类型的值,所以,咱们没法用字面量来为通道类型的变量赋值。只能经过调用内建函数make来达到目的。make参数可接受两个参数,第一个参数是表明了将被初始化的值的类型的字面量(例: chan int),而第二个参数则是值的长度,例如,若咱们想要初始化一个长度为5且元素类型为int的通道值,则须要这样写:
make(chan int, 5)
make函数也能够被用来初始化切片类型或字典类型的值。
暂存在通道值中的数据是先进先出。下面,咱们声明一个通道类型的变量,并为其赋值:
ch1 := make(chan string, 5)
这样一来,咱们就可使用接受操做符<-向通道值发送数据了。固然,也可使用它从通道值接收数据,例如,若是咱们要向通道ch1 发送字符串"value1",那么应该这样作:
ch1 <- "value1"
若是咱们从ch1那里接收字符串,则要这样:
<- ch1
咱们能够把接受到字符串赋给一个变量,如:
value := <- ch1
与针对字典值的索引表达式同样,针对通道值的接受操做也能够有第二个结果值:
value, ok := <- ch1
这里的ok的值是bool类型的。它表明了通道值的状态,true表明通道值有效,而false则表明通道值已无效(或称已关闭),更深层次的缘由是,若是在接受操做进行以前或过程当中通道值被关闭了,则接收操做会当即结束并返回一个该通道值的元素类型的零值。
能够经过函数close来关闭通道:
close(ch1)
对通道值的重复关闭会引起运行时异常,会使程序崩溃。在通道值有效的前提下,针对它的发送操做会在通道值已满(其中缓存的数据的个数已等于它的长度)时被阻塞。而向一个已被关闭的通道值发送数据会引起运行时异常。针对有效通道值的接收操做会在它已经为空时被阻塞。通道类型属于引用类型,它的零值为nil。
上一节中的通道实际上只是Go中的通道的一种。是带缓冲的通道,或者简称为缓冲通道。
通道有缓冲和非缓冲之分,缓冲通道中能够缓存N个数据,咱们在初始化一个通道值的时候必须指定这个N,**相对的非缓冲通道不会缓存任何数据,发送方在向通道发送数据的时候会当即被阻塞。直到有一个接收方已从该通道中接收了这条数据。**非缓冲的通道值的初始化方法以下:
make(chan int, 0)
除了上述分类方法,咱们还能够以数据在通道中的传输方向为依据来划分通道。默认状况下,通道都是双向的,即双向通讯。若是数据只能在通道中单向传输,那么该通道被称做单向通道。咱们在初始化一个通道值的时候不能指定为单向。可是在编写类型声明的时候能够:
type Receiver <- chan int
类型Receiver表明了一个只从中接收数据的单向通道类型,这样的通道也被称为接收通道。在关键字chan左边的接收操做符<-表示了数据的流向。相对应的,若是咱们想声明一个发送通道类型,那么应该这样:
type Sender char <- int
此次<-被放在了chan的右边,而且“箭头”直指“通道”。咱们能够把一个双向通道赋予上述类型的变量,就像这样:
var myChannel = make(chan int, 3) var sender Sender = myChannel var receiver Receiver = myChannel
可是反过来是不行的:
var myChannel1 chan int = sender
单向通道的做用主要是约束程序对通道值的使用方式,好比,咱们调用一函数时给予它一个发送通道做为参数,以此来约束它只能向该通道发送数据。又好比,一个函数将一个接受通道做为结果返回,以此来约束调用该函数的代码只能从这个通道中接收数据。