This is a creation in Article, where the information may have evolved or changed.
1. Boolean type
var v1 boolv1 = true;v2 := (1==2) // v2也会被推导为bool类型
2. Integral type
类 型 长度(字节) 值 范 围int8 1 128 ~ 127uint8(即byte)1 0 ~ 255int16 2 32 768 ~ 32 767uint16 2 0 ~ 65 535int32 4 2 147 483 648 ~ 2 147 483 647uint32 4 0 ~ 4 294 967 295int64 8 9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807uint64 8 0 ~ 18 446 744 073 709 551 615int 平台相关 平台相关uint 平台相关 平台相关uintptr 同指针 在32位平台下为4字节,64位平台下为8字节var value2 int32value1 := 64 // value1将会被自动推导为int类型value2 =value1 //编译失败:cannot use value1 (type int) as type int32 in assignment。//使用强制类型转换可解决value2 = int32(value1)
3. Numerical operations
常规运算:+、-、*、/和%比较运算: > 、 < 、 == 、 >= 、 <= 和 !=需要注意:两个不同类型的整型数不能直接比较,比如 int8 类型的数和 int类型的数不能直接比较,但各种类型的整型变量都可以直接与字面常量(literal)进行比较,比如:
varint32varint64i, j = 1, 2if// 编译错误fmt.Println("i and j are equal.")}if i == 1 || j == 2// 编译通过fmt.Println("i and j are equal.")}
4. Bit arithmetic
x << y 左移 x >> y 右移 x ^ y 异或 x & y 与 x | y 或 ^x 取反
5. Floating-point types
Go语言定义了两个类型 float32 和 float64 ,其中 float32 等价于C语言的 float 类型,float64 等价于C语言的 double 类型。var fvalue1 float32fvalue1 = 12fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型对于以上例子中类型被自动推导的 fvalue2 ,需要注意的是其类型将被自动设为 float64 ,而不管赋给它的数字是否是用32位长度表示的。因此,对于以上的例子,下面的赋值将导致编译错误:fvalue1 = fvalue2而必须使用这样的强制类型转换:fvalue1 = float32(fvalue2)
5.1 Floating-point comparison
因为浮点数不是一种精确的表达方式,所以像整型那样直接用 == 来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。下面是一种推荐的替代方案:
import"math"// p为用户自定义的比较精度,比如0.00001funcfloat64bool { return math.Fdim(f1, f2) < p}
6. plural
复数实际上由两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag)。如果了解了数学上的复数是怎么回事,那么Go语言的复数就非常容易理解了。
6.1 Plural representation
var value1 complex64 // 由2个float32构成的复数类型value1 = 3.2 + 12ivalue2 := 3.2 + 12i // value2是complex128类型value3 := complex(3.2, 12) // value3结果同 value2
6.2 Real part and imaginary part
对于一个复数 z = complex(x, y) ,就可以通过Go语言内置函数 real(z) 获得该复数的实部,也就是 x ,通过 imag(z) 获得该复数的虚部,也就是 y 。
7. String
Go语言中字符串的声明和初始化非常简单,举例如下:
varstring // 声明一个字符串变量"Hello world"// 字符串赋值ch := str[0// 取字符串的第一个字符fmt.Printf("The length of \"%s\" is %d \n"len(str))fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
输出结果为:The length of "Hello world" is 11The first character of "Hello world" is H.
字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能在初始化后被修改,比如以下的例子:str := "Hello world" // 字符串也支持声明时进行初始化的做法str[0] = 'X' // 编译错误编译器会报类似如下的错误:cannot assign to str[0]如果想修改字符串的内容,可以通过如下的方式修改:
"hello"c := []rune//将字符串s转成rune数组c[0'x'//修改rune数组中的第一个元素为xstring//根据rune数组创建一个新的字符串fmt.Println("s2=",s2)
运行结果: s2= xello
7.1 String Manipulation
x + y 字符串连接 "Hello" + "123" // 结果为Hello123len(s) 字符串长度 len("Hello") // 结果为5s[i] 取字符 "Hello" [1] // 结果为'e'
7.2 Multi-line string
使用多行字符串需要小心,例如:s := "Hello " +"world"编译时会被自动转换成:s := "Hello "; +"world";此时会编译失败,报错:invalid operation: + untyped string 正确的多行写法是这样的:s := "Hello " + "world"Go 就不会在错误的地方插入分号。另一种写法是使用反引号 ` 作为原始字符串符号:s := `Hello world`
7.3 String Traversal
Go语言支持两种方式遍历字符串。一种是以字节数组的方式遍历:
"abc中国"len(str)for i := 0; i < n; i++ { // 依据下标取字符串中的字符,类型为byte fmt.Printf("i=%v\n", ch)}
输出结果:i=97 //ai=98 //bi=99 //ci=228 //中字的第一字节,每个中文字符在UTF-8中占3个字节i=184 //中字的第二个字节i=173 //中字的第三个字节i=229 //国字的第一个字节i=155 //国字的第二个字节i=189 //国字的第三个字节
另一种是以Unicode字符遍历,以Unicode字符方式遍历时,每个字符的类型是 rune (早期的Go语言用 int 类型表示Unicode字符),而不是byte.
"abc中国"forrange str{ //range关键字在数组中有介绍 fmt.Println(i,ch) //ch的类型为rune}
//输出结果:0 971 982 993 20013 6 22269
8. Character types
在Go语言中支持两个字符类型,一个是 byte (实际上是 uint8 的别名),代表UTF-8字符串的单个字节的值;另一个是 rune ,代表单个Unicode字符。出于简化语言的考虑,Go语言的多数API都假设字符串为UTF-8编码。尽管Unicode字符在标准库中有支持,但实际上较少使用。
9. Arrays
以下为一些常规的数组声明方法:[32]byte // 长度为32的数组,每个元素为一个字节[2*N] struct { x, y int32 } // 复杂类型数组[1000]*float64 // 指针数组[3][5]int // 二维数组[2][2][2]float64 // 等同于[2]([2]([2]float64))在Go语言中,数组长度在定义后就不可更改,在声明时长度可以为一个常量或者一个常量表达式(常量表达式是指在编译期即可计算结果的表达式)。
9.1 Elements of Access
可以使用数组下标来访问数组中的元素。与C语言相同,数组下标从0到len(array)-1,下面的示例遍历整型数组并逐个打印元素内容:
//通过for循环遍历for i := 0len(array); i++ { fmt.Println("Element""of array is", array[i])}//Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素。//当然,数组也是range的支持范围。上面的遍历过程可以简化为如下的写法:forrange array { //k相当于索引,v相当于值 fmt.Println("Array element[""]=", v) }
9.2 Value Operation
需要特别注意的是,在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本。下面用例子来说明这一特点:
func main(){ [5]int{1,2,3,4,5} modify(array) fmt.Println("In main(),array values:",array)}func[5int){ array[0] = 10 fmt.Println("In modify(),array values:",array)}
//输出结果:In modify(), array values: [10 2 3 4 5]In main(), array values: [1 2 3 4 5]
从执行结果可以看出,函数 modify() 内操作的那个数组跟 main() 中传入的数组是两个不同的实例。那么,如何才能在函数内操作外部的数据结构呢?这个就要用到后接下来要讲的数组切片.
10. Array slicing
在前一节里我们已经提过数组的特点:数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)这个非常酷的功能来弥补数组的不足,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。有点类似于java中的集合.数组切片的数据结构可以抽象为以下3个变量:一个指向原生数组的指针;数组切片中的元素个数;数组切片已分配的存储空间。
10.1 Creating an Array slice
(1)基于已存在数组创建,数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片。
varMyArray[Ten]int=[Ten]int{1, 2, 3, 4, 5, 6, 7, 8, 9, ten}//Create an array slice based on the first 5 elements of the arrayvarMyslice []int= myarray[: 5]fmt. Println ("Elements of MyArray:") for_, V: =Rangemyarray{FMT. Print (V," ")}fmt. Println ("\nelements of Myslice:") for_, v:=Rangemyslice{FMT. Print (V," ")}
//输出结果:Elements of myArray:1 2 3 4 5 6 7 8 9 10Elements of mySlice:1 2 3 4 5
Go语言支持用 myArray[first:last] 这样的方式来基于数组生成一个数组切片,而且这个用法还很灵活,比如下面几种都是合法的。a.基于 myArray 的所有元素创建数组切片:mySlice = myArray[:]b.基于 myArray 的前5个元素创建数组切片:mySlice = myArray[:5]c.基于从第5个元素开始的所有元素创建数组切片:mySlice = myArray[5:](2)通过make()函数直接创建数组切片创建一个初始元素个数为5的数组切片,元素初始值为0:mySlice1 := make([]int,5)创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:mySlice2 := make([]int,5,10) 通过cap()函数可以获取切片的分配空间,len()函数可以知道当前已存储的元素个数.
fmt.Println("len(mySlice2):"len(mySlice2))fmt.Println("cap(mySlice2):"cap(mySlice2))
//输出结果:len(mySlice2): 5cap(mySlice2): 10
当然,事实上还会有一个匿名数组被创建出来,只是不需要我们来操心而已。(3)直接在声明的时候并初始化mySlice3 := []int{8,9,10}(4)基于数组切片创建数组切片oldSlice := []int{1,2,3,4,5}newSlice := oldSlice[:3] //基于oldSlice的前3个元素创建
10.2 element traversal of array slices
操作数组的所有方法都适合数组切片,通过上面的代码也可以看得出来共有2种方式:for循环遍历,或者for循环结合range来操作
10.3 Dynamic increment and decrement of array slice elements
与数组相比,数组切片多了一个存储能力的概念,即元素个数和分配的空间可以是两个不同的值,合理地设置存储能力的值,可以大幅降低数组切片内部重新分配内存和搬送内存块的频率,从而大大提高程序性能。通过append()函数可以在切片后面追加元素,例如:mySlice = append(mySlice, 8, 9, 10) append()函数的第二个参数是个不定的参数,有点类似java中的可变参数,甚至可以追加1个数组切片mySlice2 := []int{8,9,10}mySlice = append(mySlice,mySlice2...) //注意:这3个...点不能省略,否则编译失败
10.4 Content Replication
通过copy()函数,可以将一个数组切片复制到另一个数组切片中,如果2个的数组切片不一样大,则会按其中较小的那个数组切片的元素个数进行复制.slice1 := []int{1,2,3,4,5}slice2 := []int{5,4,3}copy(slice2,slice1) //只会复制slice1的前3个元素到slice2中,slice2中的值被自动替换copy(slice1,slice2) //只会复制slice2的3个元素到slice1的前3个位置,该3个位置的值自动替换,其他的不变
11.map
在C++/Java中,map一般都以库(导包)的方式提供,在C++/Java中, 而在Go中,使用map 不需要引入任何库,并且用起来也更加方便。看下面的例子:
typePersonInfostruct{IDstringNamestringAddressstring}funcMain () {varPersondbMap[string] PersonInfo//Declaration of a Key=string,value=personinfo mapPERSONDB = Make(Map[string] PersonInfo)//Initialize with make //Insert a few data into this mappersondb["0"] = personinfo{"12345","Tom","203,..."} persondb["1"] = personinfo{"1","Jack","101,..."}//.... //Find the information for key 12345 from this mapperson, OK: = persondb["0"]//If found, then ok=true, otherwise =false ifok{FMT. Println ("Found person", person. Name,"with ID", Person.id)}Else{FMT. Println ("did not find the person") }}
//运行结果:Found person Tom with ID 12345
Statement of the 11.1map
Creation of 11.2map
(1)通过make()函数创建
var myMap map [int ] string MyMap = make (map [ int ] string ) //can also be written as a statement: MyMap: = Make (map[int]string) mymap[0 ] = "1" //assignment MyMap [1 ] = "2" result,_: = MyMap [0 ] //this uses the anonymous variable fmt. Println ( "mymap[0]=" , result) fmt. Println ( "mymap[1]=" , Mymap[1 ])
//运行结果:myMap[0]= 1myMap[1]= 2
通过make创建的时候,还可以指定其初始容量myMap2 := make(map[int]string,100)(2)方式2,通过{}赋值的方式创建
map[int]string{ 0:"张三", 1:"李四",}fmt.Println("myMap3[0]=",myMap3[0])fmt.Println("myMap3[1]=",myMap3[1])
//运行结果:myMap3[0]= 张三myMap3[1]= 李四
11.3 Deletion of elements
通过delete()函数完成,形如:delete(map变量名,map的key)如果要删除的元素没有对应的key,则什么都不发生,但是如果传入的map变量的值是 nil ,该调用将导致程序抛出异常(panic)。
11.4 Searching for elements
map通过key查找,可以返回2个变量,第一个为对应key的值,第二个为是否查找成功的bool,形如:
map[key]if ok{ //找到了,处理value}else{ //未找到}
当然,如果你很确定该key一定能够找到对应的值的话,那就可以直接使用一个变量来接收,例如:value := map[key]或者,第二个参数用匿名参数来接收,例如:value,_ := map[key]
11.5 Traversal of elements
(1)使用for循环遍历
make(map[int]int)myMap[0] = 100myMap[1] = 101myMap[2] = 102for i:=0;i<len(myMap);i++ { fmt.Println("key=",i," value=",myMap[i])}
运行结果:key= 0 value= 100key= 1 value= 101key= 2 value= 102
(2)使用for循环结合range关键字遍历
map[int]int{ 0 : 10, 1 : 20, 2 : 30,}forrange myMap{ fmt.Println("key=",k," value=",v)}
运行结果:key= 0 value= 10key= 1 value= 20key= 2 value= 30