go语言基础汇总

安装完成之后打开 cmd ,输入go version 成功输出版本号则代表安装成功

Go 环境变量
关于 Go 的环境变量的问题 seaconch 就在刚才突然想到了比较贴切的形容方式

1. GOROOT

GOROOT 常被描述为 Go 编译器的路径

GOROOT 不需要我们去配,一般安装 GO 编译器时选择的路径就是 GOROOT 路径

seaconch 补充一点:import 包时,原生 pkg 也是根据 GOROOT 来引用的

所以说使用过 npm 的同学可以理解为:全局包路径

2. GOPATH

GOPATH 常被描述为 Go 源码(工程)路径

GOPATH 需要我们去手动配置,当然如果只是随便写个 demo 练手,不配也无妨

seaconch 认为 GOPATH 有点像 npm 的本地包路径

在 a.go 所在路径运行 cmd 输入 go run a.go

可以看到成功输出了 seaconch.

调试神器,无需 build 直接执行代码;在特殊情况下需要批量 run,例如 go run main1.go main2.go

注: main1.go 与 main2.go 同包 并属于 extension 关系

go build xxx.go

编译源码,生成可执行程序;在特殊情况下需要批量编译,例如 go build main1.go main2.go

go install

编译生成项目可执行文件,默认生成在 GOPATH 目录下的 bin 目录中

字符串
截取字符串:

_str := "hello seaconch."

    fmt.Println(_str[:]) -> hello seaconch.

    fmt.Println(_str[7:]) -> eaconch.

    fmt.Println(_str[:8]) -> hello se

    fmt.Println(_str[7:8]) -> e

数组与切片

Go语言中数组是值语义。一个数组变量即表示整个数组,它并不是隐式的指向第一个元素的指针(比如C语言的数组),而是一个完整的值。当一个数组变量被赋值或者被传递的时候,实际上会复制整个数组。

数组的大小是其类型的一部分,不同长度或不同类型的数据组成的数组都是不同的类型,类型 [10]int 和 [20]int 是不同的。

切片是可以动态增长和收缩的序列,切片通过对数组进行封装,为数据序列提供了更通用、强大而方便的接口。若某个函数将一个切片作为参数传入,则它对该切片元素的修改对调用者而言同样可见, 这可以理解为传递了底层数组的指针。

切片的容量可通过内建函数 cap 获得,它将给出该切片可取得的最大长度。

尽管 Append 可修改 slice 的元素,但切片自身(其运行时数据结构包含指针、长度和容量) 是通过值传递的。所以append时需要使用返回值重新赋值:

我们还可以定义一个空的数组,长度为0的数组在内存中并不占用空间。

var d [0]int // 定义一个长度为0的数组

var f = [...]int{} // 定义一个长度为0的数组

if 和 switch 像 for 一样可接受可选的初始化语句;没有圆括号,而其主体必须始终使用大括号括住。

if err := file.Chmod(0664); err != nil {

    log.Print(err)

} else { // else必须跟在右括号后面,不能在下一行

    ...

}

变量的初始化和变量的赋值类似,只是在变量声明的时候直接给出赋值,在golang中支持三种初始化的方式:

var 变量 变量类型 = 初值 
var 变量 = 初值 
变量 := 初值 
例如下面:

var v1 int = 10  //最规矩的写法
var v2 = 10 //编译器自动推算v2类型
v3 := 10    //同时进行变量的声明和初始化工作

在 Go 语言当中,变量的操作有三个比较明显的特色

:= 该方式只适用于未被 define 过的变量,并且只可以在 func 内部使用
_ 因为 Go 语言中,多返回值特别常见,当我们只需要多个返回值之中的个别值时,可以采用 name, _ := 方法() 的方式可以舍弃第二个返回值,这种类似的方式达到想要的效果,多赋值情况下,默认不赋值的常量使用上一个常量的值

通过使用 iota 来表示枚举:

const (
    sunday = iota
    monday
    tuesday
    wednesday= 88
    thursday 
    friday = iota
    saturday
)

sunday -> 0

monday -> 1

tuesday -> 2

wednesday -> 88

thursday -> 88

friday -> 5

saturday -> 6

可以看出 iota 的作用了吧, iota 有一点像是一个计数器,seaconch 抛砖引玉,用这个小例子来说明其用途


要特别注意”:=”这个在c,c++,java中都未曾出现过的符号,他可以缩短代码的行数,编译器应该是将这句话解释成为两句,var v3 int , v3 = 10 
所以”:=”的左侧要是一个没有被声明过的变量,否则会下面的错误, 要特别注意

no new variables on left side of :=

1.3 Golang中匿名变量的概念
用过matlab这种解释语言的读者应该对一个函数的多返回值有印象,在c,c++中如果要想返回多个值,要么是返回一个类型,结构体,或者在形参中传入要返回变量类型的指针。这些在golang中直接支持了函数多返回值这样一种方式,但是,如果多返回值中有些是我们不需要的那么怎么办,和matlab类似,这里引入了匿名变量,”_”,其实就是作为一种缺省。例如书中的列子:

func GetName() (firstName, lastName, nickName string) {
    return "may", "chan", "haha"
}
_, _ ,nickname := GetNmae() //这里面就是一种缺省,值用来获得nickName

2. Go中的常量
Go中也是用const来进行常量的定义,例如

const str string = "hellotest” //string类型
const  number int32 = 1234  //32位整形常量等
const (  //枚举类型,减少const的书写
    zero = 0.0
    eof = -1
)

整数
int 整形,会根据 cpu & ide 决定 64 / 32

uint 无符号 int

byte == uint8 可以理解为类型别名

rune == int32 可以理解为类型别名

浮点
float32 / float64 精度不同

复数跳过

布尔型
布尔型有两点需要主要:

默认值为 false

Golang 中1 与 true 0 与 false 没有可比性


除此之外,还有预定义的变量,包括bool型”true”,”false”等以及自动增长的iota。 
其中iota在出现const的时候被置0,之后没出现一次iota自动加1,直到被重新置0为止。例如

const (                     //iota被重设为0
        a = iota            //a = 0
        b = iota            //b=1
        c = iota            //c=2


注意上面因为是枚举,可以简化为

const (                     //iota被重设为0
        a = iota            //a = 0
        b                   //b=1
        c                   //c=2


1.3 Go支持的类型
先来看看Go支持的基础类型,然后我们围绕一些类型来介绍go中首创的,新鲜的一些特性。 
和其他类型一样,go支持:

布尔型 bool 
整形 int8, byte, int16, int, uint, uintptr 
浮点类型: float32 (c中的float ), float64 ( c中的double ) 
复数类型: complex64, complex128(go中特有的) 
字符串: string (内置类型) 
字符类型: rune(Unicode字符类型), byte(UTF-8字符类型) 
错误类型: error 
以及复合类型: 
指针: pointer 数组: array 切片: alice 
字典: map 通道: chan 结构体: struct 接口: interface 
等 
下面我们分别介绍一下这些类型的使用注意事项:

1) bool类型,
在bool类型中,不像c中那样,对一个bool类型的变量只能赋值,true或者false。或者是比较运算。不能直接赋值0,1,也不能对0,1进行强制类型转换,例如

var v1 bool = true//正确
var b bool = (1==2) // 正确
var f1 bool = 1 // false
var f2 bool = bool(1) //错误

2) 整形
在整形中,go分别支持8,16,32,64bit的有符号和无符号整形。其中 unit8 就是byte,类似于c语言中的char型。还有就是int和int32在go语言里是两种不同的类型,所以这两种类型的变量也不可以相互赋值以及进行运算。如果进行运算的话需要进行强制类型转换。同时go中的整形与C语言类似,也支持数值运算,比较运算,以及位运算。除了位运算中的取反是使用^x 以外,C语言是使用~x,其他和C语言完全一样。

3) 浮点型
在浮点型中,go中定义了float32, float64两种,其中float32等价于C中的float,float64等价于C语言中的double。同时,在Go中,定义一个浮点数变量的时候,如果没有显示声明类型,编译器在自动推算的时候会将变量声明为float64而不是float32,例如:

fvalue := 12.0   //这里fvalue有编译器自动识别为float64

还有就是,浮点数中的判断相等比较的时候,因为浮点数的精度问题,所以不能直接用“==”来进行两个变量的判断,在math库中提供了,math.Fdim(var1,var2)来对两个变量的差值进行判断。

4) 复数类型
复数类型是go中引入的一种新的内置的数据类型,其中complex64表示用实部和虚由float32构成,complex128类推。复数的可以有下面3中使用方法:

var value1 complex64 = 3.2 + 12i
value2 := 3.2 + 12i
value3  := complex(3.2, 12)
 r = real(value1)       //获得复数的实部
 i  = imag(value1)    //获得复数的虚部

5) 字符串和字符类型
在go中,字符串是一种内置的类型,和C++中的包类似,可以使用数组下标的形式获取字符,但是注意,不能用这种方式对字符进行修改。例如下面的用法:

var str string           //声明一个string类型的变量
str = "String Test"     //赋值
ch := str[0]           //获取第一个元素的值
length = len(str)     //字符串的长度
str[0] = 's'         //出错XXXX。不能这样来赋值
str = str + "Haha"  // 字符串的链接

在这里还需要注意的是,golang中只支持UTF-8以及Unicode的编码,而对于其他的编码并没有内置的编码转换,所以在我们保存的时候需要很小心,尤其是中国地区可能默认的保存的编码方式是GBK,这里提供七牛云存储团队自己搞的一个转换的源码: https://github.com/xushiwei/go-iconv 
关于UTF-8的编码是用byte这种类型来定义的,Unicode是用rune来定义的。所以要注意字符的编码方式,尤其是在字符串遍历的时候,如果使用range关键字,那么使用的是rune的形式来遍历的。而以数组取值的方式是byte的形式。

6)数组与数组切片
golang中的数组和c语言中的数组在一定程度上是一样的,包括元素的访问等,都是从0到len-1; 
但是golang中的数组有几个新的特性,包括: 
a. 可以使用len获得数组的长度 
b. 可以使用range来遍历访问容器中的元素,类似于foreach.例如

for i, v := range array { 
    fmt.Println("Array element ['', i , '']=", v)
}  //两个返回值

c. golang中的数组是值类型,和c语言中的数组名代表的是首地址不同。所以在传递数组的时候,不会改变原数组中的值,并且因为是值传递,所以每次都会进行一次形参值得copy。而这明显降低了函数调用的效率和空间的浪费。所以在golang中还提供了数组切片的功能。 
数组切片(slice)可以认为是关联某个数组的一个数据结构,这个数据结构包含以下三部分:

其所关联的数组的指针; 
数组切片中数组的元素的个数;(即实际包含的数组元素的个数) 
数组切片分配了的存储空间;(含有多大的空间) 
下面是创建数组切片的三种方式:


one way:基于原生数组创建

var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  
var mySlice [ ]int = myArray[:5]  

second way: 使用make直接创建

mySlice1 := make([ ]int,5)  //出事元素个数是5,且都为0
mySlice2 := make([ ]int, 5, 10)  //容量是10
mySlice3 := [ ]int{1,2,3,4,5}  //元素是1,2,3,4,5的切片。

third way: 基于已有的切片进行创建

oldSlice := []int{1, 2, 3, 4, 5}
newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片

对数组切片的操作: 
append函数用来附加;copy函数用来进行复制。

mySlice2 := []int{8, 9, 10} // 给mySlice后面添加另一个数组切片
mySlice = append(mySlice, mySlice2...)//注意mySlice2后面的...不能省
//等价于:
mySlice = append(mySlice,8,9,10)

map是golang中内置的一种数据类型,与C++ STL中的map不同的是,这里的map没有按照键值对排序。(不知道为什么要这样,知道的读者也可以告诉我为什么不排序,那样的话查找不是很慢吗?可能插入删除会快些,这里面是个trade off?) 
map的使用包含如下几个方面:

a. 声明和创建,使用map,make关键词 
var map变量名 map[key的类型] value的类型 = make (map[key的类型] value的类型,元素容量) 其中元素容量参数可省。 
例如: 
var myMap map[string] PersonInfo = make (map[string] PersonInfo,100)

b. 初始化和赋值 
可以在创建map变量的时候直接初始化, 
myMap = map[string] PersonInfo { 
“1234”: PersonInfo{“1”, “Jack”, “Room 101, …”}, 

或者直接给key赋值: 
myMap[“1234”] = PersonInfo{“1”, “Jack”, “Room 101, …”}

c. 元素的删除 
直接使用delete(map容器,key值)函数,删除容器内的元素。例如:delete(myMap, “1234”);

d. 元素的查找 
golang中的map查找直接通过数组访问的形式,例如: 
value, ok := myMap[“1234”] 
if ok { // 找到了 
// 处理找到的value 

可以看到,返回值是两个,其中value是待查找的元素的key存在情况下的值

猜你喜欢

转载自blog.csdn.net/weixin_42322206/article/details/88833774