Golang 笔记 1 基础、基本数据类型
一、Go语言基础1. 基础Go语言中的标识符必须以字母(Unicode字母,PHP/JS可以用中文作为变量名)下划线开头。大写字母跟小写字母是不同的:Hello和hello是两个不同的名字。
??如果一个名字是在函数内容定义,那么它的作用域就在函数内容,如果在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头,那么它可以被外部的包访问,例如fmt包的Printf函数。 2. 注释
3. Go程序的一般结构
4. 可见性规则??Go语言中使用大小写来决定该常量、变量、类型、接口、结构或函数是否可以被外部包所调用: 根据约定,函数名首字母小写即为private(外部不可以调用),大写为public 二、基本数据类型1、变量和常量
2、整数类型的命名和宽度??Go的整数类型一共有10个 ??除了这两个计算架构相关的整数类型之外,还有8个可以显式表达自身宽度的整数类型: 3、整数类型值的表示法?? ??如果以8进制为变量num赋值:
??如果以16进制为变量num赋值:
4、浮点数类型??浮点数类型有两个:float32/float64 ??浮点数类型的值一般由整数部分、小数点"."和小数部分组成。另外一种表示方法是在其中加入指数部分。指数部分由"E"或"e"以及带正负号的10进制整数表示。例:3.9E-2表示浮点数0.039。3.9E+1表示浮点数39。 5、复数类型??复数类型有两个:complex64和complex128。实际上,complex64类型的值会由两个float32类型的值分别表示复数的实数部分和虚数部分。而complex128类型的值会由两个float64类型的值表示复数的实数部分和虚数部分。 6、byte与rune??byte与rune都属于别名类型。byte是uint8的别名类型,而rune是int32的别名类型。 ?? ? 另外在rune类型值的表示中支持几种特殊的字符序列,即:转义符。如下图:? ?? 7、字符串类型??字符串的表示法有两种,即:原生表示法和解释型表示法。原生表示法,需用用反引号"`"把字符序列包起来,如果用解释型表示法,则需要用双引号"""包裹字符序列。
??二者的区别是,前者表示的是所见即所得的(除了回车符)。后者所表示的值中转义符会起作用。字符串值是不可变的,如果我们创建了一个此类型的值,就不可能再对它本身做任何修改。 三、高级数据类型1、数组类型??一个数组是可以容纳若干相同类型的元素的容器。数组的长度是固定的。如下声明一个数组类型:
??上面这条类型声明语句实际上是为数组类型[3]int声明了一个别名类型。这使得我们可以把MyNumbers当作数组类型[3]int来使用。
??现在我们把这个数组字面量赋给一个名为numbers的变量:
??另一种方式是在其中的类型字面量中省略代表其长度的数组,例:
??可以用如下方式访问该变量中的任何一个元素。例:
??如果要修改数组值中的某一个元素值,可以:
??可以用如下方式获取数组长度:
??如果一个数组没有赋值,则它的默认值为[length]type{0,0...} 2、切片类型(1) 基础??切片(slice)与数组一样也是可以若干相同类型元素的容器。与数组不同的是切片类型的长度不确定。每个切片值都会将数组作为其底层数据结构。表示切片类型的字面量如:
或者是:
??切片类型的声明可以这样:
??对切片值的表示也与数组值相似
??操作数组值的方法同样适用于切片值。还有一种操作数组的方式叫做“切片”,实施切片操作的方式就是切片表达式。例:
??上例中切片表达式numbers3[1:4]的结果为[]int{2,3,4}很明显被切下的部分不包含元素上界索引指向的元素。实际上slice1这个切片值的底层数组正是number3的值。
??除了长度切片值以及数组值还有另外一个属性--容量。数组的容量总是等于其长度,而切片值的容量往往与其长度不同。如下图:? ?? ??如图所示,一个切片值的容量即为它的第一个元素值在其底层数组中的索引值与该数组长度的差值的绝对值。可以使用cap()内建函数获取数组、切片、通道类型的值的容量:
??切片类型属于引用类型,它的零值即为nil,即空值。如果我们只声明了一个切片类型而不为它赋值,则它的默认值:nil。 (2) 切片的更多操作方法??有些时候我们可以在方括号中放入第三个正整数。如下图所示:
??第三个正整数为容量上界索引,它意义在于可以把作为结果的切片值的容量设置的更小。它可以限制我们通过这个切片值对其底层数组中的更多元素的访问。上节中numbers3和slice的赋值语句如下:
??这时,变量slice1的值是[]int{2,4}。但是我们可以通过如下操作将其长度延展与其容量相同:
??通过此操作,变量slice1的值变为了[]int{2,4,5},且其长度和容量均为4。现在number3的值中的索引值在(1,5)范围内的元素都被体现在了slice1的值中。这是以number3的值是slice1的值的底层数组为前提的。这意味着我们可以轻而易举地通过切片访问其底层数组中对应索引值更大的更多元素。如果我们编写的函数返回了这样一个切片值,那么得到它的程序很可能会通过这种技巧访问到本不应该暴露给它的元素。
??那么在此之后,我们将无法通过slice1访问到number3的值中的第五个元素。
??通过上述操作,slice1的值变为了[]int{2,6,7}。一旦扩展操作超出了被操作的切片值的容量,那么该切片的底层数组就会被替换???最后一种操作切片的方式是“复制”。该操作的实施方法是调用copy函数。该函数接收两个类型相同的切片值作为参数,并把第二个参数值中的元素复制到第一个参数值中的相应位置(索引值相同)上。这里有两点需要注意:
??例:
?通过上述复制操作,slice4会变成[]int{2,7,0}。 3、字典类型??Go语言的字典(Map)类型是一个哈希表的实现。字典类型的字面量如下:
??其中,"K"为键的类型,而"T"则代表元素(值)的类型。如果我们描述一个键类型为int,值类型为string的字典类型的话:
??字典值的字面量表示法实际上与数组的切片的字面量表示法很相似。最左边仍然是类型字面量,右边紧挨着由花括号包裹且有英文逗号分隔的键值对。每个键值对的键和值之间由冒号分隔。以字典类型map[int]string为例。他的值的字面量可以是这样的:
??我们可以把这个值赋给一个变量
??可用索引表达式取出字典中的值:
??可以用索引表达式赋值:
??这样mm中键为2的值变为了"b2"。可以用如下方式向字典中添加一个键值对:
??对于字典值来说,如果指定键没有对应的值则默认为该类型的空值。所以mm[5]会返回一个""。但是这样的话我们就不知道mm[5]到底是""还是mm[5]没有这个值。所以go提供了另外一种写法:
??针对字典的索引表达式可以有两个求职结果,第二个求职结果是bool类型的。它用于表明字典值中是否存在指定的键值对。 ??从字典中删除键值对的方法非常简单,仅仅是调用内建函数delete:
??无论mm中是否存在以4为键的键值对,delete都删除。 ??字典类型属于引用类型,它的零值即为nil 4、通道类型??通道(Channel)是Go语言中一种非常独特的数据结构。它可用于在不同Goroutine之间传递类型化的数据。并且是并发安全的。相比之下,之前几种数据类型都不是并发安全的。
??在这个类型字面量中,左边是代表通道类型的关键字chan,而右边则是一个可变的部分,即代表该通道类型允许传递的数据的类型(或称通道的元素类型)。
??make函数也可以被用来初始化切片类型或字典类型的值。
??这样一来,我们就可以使用接受操作符<-向通道值发送数据了。当然,也可以使用它从通道值接收数据,例如,如果我们要向通道ch1 发送字符串"value1",那么应该这样做:
??如果我们从ch1那里接收字符串,则要这样:
??我们可以把接受到字符串赋给一个变量,如:
??与针对字典值的索引表达式一样,针对通道值的接受操作也可以有第二个结果值:
??这里的ok的值是bool类型的。它代表了通道值的状态,true代表通道值有效,而false则代表通道值已无效(或称已关闭),更深层次的原因是,如果在接受操作进行之前或过程中通道值被关闭了,则接收操作会立即结束并返回一个该通道值的元素类型的零值。
??对通道值的重复关闭会引发运行时异常,会使程序崩溃。在通道值有效的前提下,针对它的发送操作会在通道值已满(其中缓存的数据的个数已等于它的长度)时被阻塞。而向一个已被关闭的通道值发送数据会引发运行时异常。针对有效通道值的接收操作会在它已经为空时被阻塞。通道类型属于引用类型,它的零值为nil。 5、通道的更多种类??上一节中的通道实际上只是Go中的通道的一种。是带缓冲的通道,或者简称为缓冲通道。
??除了上述分类方法,我们还可以以数据在通道中的传输方向为依据来划分通道。默认情况下,通道都是双向的,即双向通信。如果数据只能在通道中单向传输,那么该通道被称作单向通道。我们在初始化一个通道值的时候不能指定为单向。但是在编写类型声明的时候可以:
??类型Receiver代表了一个只从中接收数据的单向通道类型,这样的通道也被称为接收通道。在关键字chan左边的接收操作符<-表示了数据的流向。相对应的,如果我们想声明一个发送通道类型,那么应该这样:
??这次<-被放在了chan的右边,并且“箭头”直指“通道”。我们可以把一个双向通道赋予上述类型的变量,就像这样:
??但是反过来是不行的:
??单向通道的作用主要是约束程序对通道值的使用方式,比如,我们调用一函数时给予它一个发送通道作为参数,以此来约束它只能向该通道发送数据。又比如,一个函数将一个接受通道作为结果返回,以此来约束调用该函数的代码只能从这个通道中接收数据。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |