Go语言基础

分号 : 如果希望将两个或多个语句放在同一行,必须用分号分隔;一般情况下,不需要分号。

Go程序是通过包来组织的,包名为main的是一个可独立运行的包,编译后产生可执行文件。main包的main函数是程序的入口,是个没有参数也没有返回值的函数。

可以使用GOPATH环境变量或是使用相对路径来import自定义的package。Go约定如下:
1. 在import中,可以使用相对路径如./../来引用自定义包;
2. 如果没有使用相对路径,那么Go会去$GOPATH/src/目录查找。

变量与常量

变量声明

  1. 类型是后缀的,有时可以省略;
  2. 以var关键字开头,有时可以省略的;
  3. 自动类型推断;
  4. 可以平行定义多个变量;

举例:


var count int                                   // 声明
var total  int = 42                            // 声明并初始化
var total,  avg int  =  42,  20             // 同时声明并初始化多个变量
var a, b * int                                   // 声明两个int类型指针
var label = "string value"                  // 省略了类型,编译器自动推断
i := 123                                          // 定义并初始化
i, str := 123, "string value"             // 平行定义,还可用用函数的返回值来定义

:=只能在函数内部使用,在函数外使用会出现编译错误;一般用var方式定义全局变量。

多个var声明可以成组,组用小括号,const和import也这样做。如:


import(
    "fmt"
    "os"
)

const(
    i = 100
    pi = 3.1415
    prefix = "Go_"
)

var(
    i  int
    pi  float32
    prefix  string
)

当定义一个变量时,它默认赋值为其类型的null值。如,var a inta的值是0var s strings被赋值为零长度的字符串,也就是""

一个特殊的变量名是 _ (下划线),任何赋值给它的值都被丢弃。所以 _ 可以说是属于任何类型的。

声明但未使用的变量在编译时将报错。

### 常量
常量在编译时被创建,只能是数字、字符串或布尔值。


const (
    a = iota
    b = iota
)

iota可以生成数值的递增的枚举值。iota第一次使用时是0,以后每次使用值增加1。


const (
    a = iota
    b           // 隐式的 b = iota
    b string  // 明确指定类型
)

数据类型

布尔类型

布尔类型表示由预定义常量truefalse代表的布尔判定值。布尔类型是bool

数字类型

int 和 uint类型的长度取决于硬件平台。但只会是32或64位之一。

完整的整数类型列表:
有符号: int8, int16, int 32, int64
无符号: byte, uint8, uint16, uint32, uint64。
rune 是int32的别名,byte是uint8的别名。

浮点类型的值有float32和float64。(没有float类型)

64位的整数和浮点数总是64位的,即使是在32位的架构上。

这些类型都是独立的,混合使用这些类型向变量赋值会引起编译器错误。

rune

rune 是int32的别名,用UTF-8编码。 在需要遍历字符串中的字符,为了获得实际的字符,需要使用rune类型。

string

字符串是用双引号或反引号包裹的字符序列,是不可变的,UTF-8编码。可以用+操作符来连接两个字符串。

用反引号作为原始字符串符号:
<pre><code>
s :=
start part
ending part`

现在s包含换行。

不像转义字符串标识,原始字符串标识的值在引号内的字符是不转义的。

复数

Go原生支持复数,complex128和complex64,虚数部分分别有64、32位。复数写为:RE + IMi,RE是实数部分,IM是虚数部分。


    var comp complex64 = 4 + 5i
    fmt.Printf("value is : %v", comp)

将打印 (4+5i)

类型转换

Go不支持隐式的类型转换,所有的类型转换都必须是显式的。类型转换的方式:v dstType := dstType(srcVal)


bytes []byte := []byte("string value")          // 字符串到字节数组的转换
str := string(bytes)                                   // 字节数组到字符串的转换
ui := uint32(-128)                                     // 有符号数到无符号数的显式转换

运算符

go-operator

表格中没有列出的还有逻辑非 !

&^ 表示位清除。

运算符都是从左到右结合的。Go不支持运算符重载。

Go保留字

go-reserve-keyword

array、slices、map

array

array 由[len]type 定义,len表示数组的长度,type表示存储元素的类型。对array元素的赋值或索引是由括号[]完成的。


var arr [10]int
arr[0] = 43
arr[1] = 20

大小是类型的一部分,不同大小的是不同类型,因此不能改变大小。

数组同样是值类型,将一个数组赋值给另一个数组,会复制所有的元素。当向函数内传递一个数组的时候,它会获得一个数组的副本,而不是数组的指针。

[]内可显示指定数组长度,也可用 ... 代替,在{}里写数组元素,使用3个句点时,Go自动计算数组元素的个数。


a := []int {1, 2, 3}                         // 声明了长度为3的数组
b := [10]int{1, 2, 3}                      // 声明了长度为10的数组,前3个元素的值分别为1,2,3,其余元素的值为0。
c := [...]int{4, 5, 6}                       // 采用`...`的方式,Go根据元素个数来计算数组长度。

a2 := [2][2]int{ [...]int{4, 5}, [...]int{8,9} }          // 二维数组
a3 := [2][2]int{ {4, 5}, {8,9} }                            // 二维数组,简化的声明方式

slice

slice与array接近,但在新的元素加入的时候可以增加长度。slice总是指向底层的一个数组。slice是一个指向数组的指针,是引用类型。slice总是与一个固定长度的array成对出现,其影响slice的容量和长度。

切片可以在数组或已有切片上创建:var s = arr[start : end],区间为:[start, end),start和end都可以省略,冒号:不能省略,start默认为0,end默认为数组或切片的长度。

s1 := make([]int, 10) 创建一个保存10个元素的slice。


var  s  []int                         //  声明一个slice,不需要长度。
s  :=  []byte{'a', 'b', 'c'}       //  声明并初始化。

var array = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}     //  声明一个数组

sa :=  array[:]                      //  定义一个slice,它的元素是数组ar的所有元素。
aSlice := array[:3]                // 等价于aSlice = array[0:3] aSlice包含元素: a,b,c
aSlice := array[5:]                // 等价于aSlice = array[5:10] aSlice包含元素: f,g,h,i,j
aSlice := array[:]                  // 等价于aSlice = array[0:10] 这样aSlice包含了全部的元素

var arr[m] int
slice := arr[0 : n]
此时,len(slice) == cap(slice) == n
len(arr) == len(arr) == m

对于slice有几个有用的内置函数:

  • len:获取slice的长度
  • cap:获取slice的最大容量
  • append:向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice
  • copy:函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数

注:append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。 但当slice中没有剩余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响。

map

map也是一种引用类型。一般定义map的方法是: map[key_type] value_type

mapv := map[string]int {"key" : 1, "key2" : 2, } 最后的逗号是必须的。

当只需要声明一个map时候,使用make形式: monthdays := make( map[string]int )

检查元素是否存在,可用这种形式:value, present = monthdays["Jan"]

删除元素: monthdays["Mar"] = 0, false或者delete(monthdays, "Mar")

添加元素: monthdays["Feb"] = 29

流程控制

流程控制分三大类:条件判断,循环控制和无条件跳转。

控制结构的条件判断无需小括号,而语句体必须总是包含在大括号内。

条件语句 if


if [init stmt;] condition {
    // true statements
} else {
    // false statements
}

//  if和switch接受初始化语句,通常用于设置一个(局部)变量。
if err := file.Chmod(0664); err != nil {        // 左大括号必须放在行尾
        log.Stderr(err)
        return err
}

goto

goto 跳转的目标一定是当前函数内定义的标签。标签的定义:单独一行,此行第一个词,以冒号结束,标签名大小写敏感。


func mufunc() {
    i := 0
    Here:        // 此行第一个词,以冒号结束为标签
    println(i)
    i++
    goto Here   // 跳转
}

循环语句 for

for循环有三种形式,只有一种使用分号。


for init; condition; post {}        //  和C的for一样
for condition {}                       //  和while一样
for {}                                     //  死循环

for i, j := 0, len(a) - 1; i < j; i, j = i + 1, j - 1 {        // 结合使用平行赋值
    a[i], a[j]= a[j], a[i]
}

break、continue

break提前退出循环,continue终止当前的循环。

循环嵌套循环时,可以在break后指定标签,用标签决定哪个循环被终止。

break和continue还可以跟着标号,用来跳到多重循环中的外层循环。

range

range可用于在slice、array、string、map、channel上循环。range是个迭代器,当被调用的时候,从它的循环的内容中返回一个键值对,基于不同的内容,range返回不同东西。

当对slice或array做循环时,range返回序号作为键,序号对应的内容作为值。

分支语句 switch

switch 表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项,如果没有表达式,会匹配true

fallthrough 可以使匹配的分支执行完后继续执行紧邻的下一个分支的语句。

分支可以使用逗号分隔的列表,表示匹配多个值中的一个:case '0', '1' : stements;,表示匹配'0', '1'中的一个。

default可以指定其他所有分支都不匹配时的行为。

举例:


var result int
switch byte {
case 'a', 'b':               // 逗号分割列表
  result = 1
default:
  result = 0
}

switch result := calculate(); true {
case result < 0:                                   //  不再局限于匹配整数、字符
  /* negative */
case result > 0:
  /* positive */
default:
  /* zero */
}

欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据