Go语言——基础

版权声明:本文为博主原创文章,需转载可以私信我,同意后即可 https://blog.csdn.net/Sun_White_Boy/article/details/84935521

Go基础

变量

Go变量使用方式和C语言接近,但具备更大的灵活性

变量声明

对于纯粹的变量声明,Go引入了var关键字,类型信息放在变量名之后,示例如下:

var v1 int
var v2 string
var v3 [10]int            // 数组
var v4 []int              // 数组切片
var v5 struct {
    f int
}
var v6 *int               // 指针
var v7 map[string]int     // map, key为string类型,value为int类型
var v8 func(a int) int 

为了避免重复写var,可以将若干个需要声明的变量放在一起,如下:

var (
    v1 int
    v2 string
)

变量初始化

初始化例子如下:

var v1 int = 10       // 用法1
var v2 = 10           // 用法2 编译器可以自动推导出v2的类型
v3 := 10              // 用法3 编译器可以自动推导出v2的类型

注意:
第三种方法不能用于声明全局变量

即使第三种初始化方法很像动态语言,比如Python,但是Go是强类型语言(静态语言)

变量赋值

Go支持多重复值,所以可以实现直接交换两个数的值操作

i, j = j, i

匿名变量

在一般强类型语言中,如果函数返回多个值,那么需要定义多个多余的变量,在Go中,可以使用匿名变量代替你不需要的变量

例如,GetName()返回三个值,但是你只需要最后一个值

-, -, nickName = GetName()

常量

常量指不可以更改的值

字面常量

程序中硬编码的常量,如:

-12
3.2132131231232        // 浮点型常量
3.2+12i                // 复数型常量
true                   // 布尔型常量
"foo"                  // 字符串常量

常量定义

与C语言一样,使用const关键字定义常量

const Pi float64 = 3.14159263123213213
const zero = 0.0                         // 无类型浮点常量
const (
    size int64 = 1024
    eof = -1                            // 无类型整形常量
)
const u, v float32 = 0, 3              // 常量的多重赋值

Go可以定义常量的类型,也可以定义无类型常量.

常量的右值可以是一个常量表达式,因为常量的赋值是编译期行为,所以右值不可以是一个运行期表达式

预定义常量

Go预定义了这些常量: true、false和iota

true和false比较常见 用法也是类似的

这里详细说一下iota:
iota比较特殊,可以被认为是一个可被编辑器修改的常量,在每个const出现后iota重置为0,在下一个const出现之前,没出现一次iota,其代表的数字加1,下面举个例子:

const (
    c0 = iota  // c0 = 0
    c1 = iota  // c1 = 1
    c2 = iota  // c2 = 2
)
const (
    c0 = iota*2  // c0 = 0
    c1 = iota*2  // c1 = 2
    c2 = iota*2  // c2 = 4
)

如果下面的赋值表达式相同,那么可以省略,比如上面第一个表达式可以写成:

const (
    c0 = iota  // c0 = 0
    c1         // c1 = 1
    c2         b// c2 = 2
)

枚举

枚举指一系列相关的常量,比如下面关于一个星期中每天的定义:

const (
    Sunday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    numberOfDays   // 这个常量没有导出
)

以大写字母开头的常量在包外可见,以上例子中numberOfDays为包内私有,其他符号可以被其它包访问

类型

Go包含以下基础类型:

  • 布尔类型: bool
  • 整形: int8, byte, int16, int, uint, uintptr等
  • 浮点类型: float32, float64.
  • 复数类型: complex64, complex128
  • 字符串: string
  • 字符类型: rune
  • 错误类型: error
    此外,还包含以下这些复杂类型:
  • 指针 ( pointer )
  • 数组 ( array )
  • 切片 ( slice )
  • 字典 ( map )
  • 通道 ( chan )
  • 结构体 ( struct )
  • 接口 ( interface )

布尔类型

关键字bool,可赋值为预定义的true和false

布尔类型不接受其他类型的赋值,不支持自动或强制的类型转换

整形

整形是所有语言中最基础的类型
包括有符号的整形 int8 int16 int32 int64以及对应的无符号整形数 uint8 uint16 uint32 uint64 这里面的数字 8,16,32,64对应的是计算机位数 。
这里对应有特定平台的有符号int型与无符号uint型 这两种类型是根据CPU的处理位数来确定对应大小的
uintptr 没有指定大小,但是可以容纳指针。

类型表示

int和int32在Go语言中是两种不同的类型,如果要进行赋值,必须进行强制转换
强制转换时需要注意

  • 数据长度被截短导致的数据进度损失问题
  • 值溢出(超过转换的目标类型的值范围)

数值运算

Go语言支持常规的整数运算:加减乘除和取余

比较运算

Go支持 >, <, ==, >=, <= 和 !=.
注意
两个不同类型的整数不能直接比较,但是各种类型的整形变量都可以直接和字面常量比较

位运算

运算 含义
x << y 左移
x >> y 右移
x ^ y 异或
x & y
x y
^x 取反

浮点型

浮点型用于表示包含小数点的数据

浮点数表示

float32等价于C中float类型,float64等价于C中double类型

浮点数比较

浮点数不是一种精确的表达方式,所以没有办法直接使用==来判断.

这里推荐一种比较的方法:

import 'math'
// 这样可以自己确认浮点数的比较精度
func IsEqual1(f1, f2, p float64) bool {
	return math.Abs(f1-f2) < p
}

复数类型

复数实际上由两个实数构成,一个表示实部,一个表示虚部.

复数表示

复数表示示例如下:

var value1 complex64

value1 = 3.2 + 12i
value2 := 3.2 + 12i
vlaue3 := complex(3.2, 12)

实部和虚部

Go中可以通过real(z)获取复数的实部,imag(z)获取复数的虚部.

字符串

字符串也是基本类型之一.

字符串操作

运算 含义
x + y 字符串连接
len(s) 字符串长度
s[i] 取字符串

更多的字符串操作,可以参考标准库strings包

字符串遍历

字符串遍历有两种方法
第一种通过下标来访问字符串

str := "Hello, everyone"
n := len(str)
for i:= 0; i < n; i++ {
	ch := str[i]
	fmt.Println(i, ch)
}

第二种类似于python中的遍历

for i, ch := range str {
	fmt.Println(i, ch)
}

字符类型

Go中包含两种字符类型,一个是byte,代表UTF-8字符串的单个字节的值;另一个是rune,代表单个Unicode字符

出于简化语言的考虑,Go语言的多数API都假设字符串为UTF-8编码.

数组

数组同样也是Go语言中最常用的数据结构之一.数组就是指一系列同一类型数据的集合.
数组的长度在定义后是无法更改的.
下面是一些常规的数组声明方法:

[32]byte                      // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 }   // 复杂类型数组
[1000]*float                  // 指针数组
[3][5]int                     // 二维数组

元素访问

可以使用数组下标来访问数组,同样也可以通过range函数来遍历数组.

range函数返回两个值,第一个是数组的下标,第二个是元素的值.

值类型

数组是值类型,如果在函数中传入数组,那么在函数中其实是数组的副本,是无法对原数组实行具体操作的.

数组切片

数据切片的数据结构可以抽象为以下3个变量:

  • 一个指向原生数组的指针
  • 数组切片中的元素个数
  • 数组切片已分配的存储空间
创建数组切片

创建数组切片的方法主要有两种 --------- 基于数组和直接创建

基于数组
var Array [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var array []int = Array[:5]
直接创建

Go中make方法可以直接创建数组切片

mySlice := make([]int, 5)
mySlice := make([]int, 5, 10)
动态增减元素

Go中有cap和len函数
cap函数用于计算数组分配的空间大小
len函数用于计算数组实际元素个数

对于动态增加元素,下面示例:

mySlice := make([]int, 5, 10)
mySlice2 := []int{8, 9, 10}
mySlice = append(mySlice, mySlice2...)   // 这里...用于把mySlice包含的元素打散

基于数组切片创建数组切片

可以直接通过对已有数组切片后创建数组切片,并且这个切片范围可以大于数组元素个数,但是不能大于数组分配的空间大小,当超出原有数组的元素,自动赋值为0

内容复制

Go语言中的copy函数可以用于数组内容的复制,如果加入的两个数组切片不一样大,那么就会按照其中较小的数组切片元素进行复制.

map

map(字典)是一对键值对的微排序集合.在python中dict数据结构类似.

变量声明

var myMap map[string] PersonInfo

myMap是声明的map变量名,string是键类型,PersonInfo是值类型

创建

通过make函数创建一个新的map.

myMap = make(map[string] PersonInfo, 100)

创建一个新的map,存储能力是100

初始化
myMap = map[string] PersonInfo{
    "1234": PersonInfo{"1", "Jack", "Room 101...."},
}

元素赋值

赋值就直接将键值对应即可

元素删除

Go语言提供一个内置函数delete(),用于删除容器内的元素.

delete(myMap, "1234")

元素查找

在python中dict查找直接使用关键字in即可.
在Go中元素查找可以这样写:

value, ok := myMap["1234"]
if ok {	    
}

流程控制

Go语言支持下面几种流程控制语句:

  • 条件语句, 对应关键字if, else 和 else if
  • 选择语句, 对应关键字switch, case 和 select
  • 循环语句, 对应关键字for和range
  • 跳转语句, 对应关键字goto
    Go还添加了如下关键字:break, continue, fallthrough

条件语句

条件语句,需要注意以下几点:

  • 条件语句不需要使用括号将条件包含起来
  • 无论语句体内有几条语句,花括号都是必须存在的
  • 在if之后,条件语句之间,可以添加变量初始化语句,使用;间隔
  • 在有返回值的函数中,不允许将"最终的"return语句包含在if…else…结构中,否则会编译失败

选择语句

选择语句与C语言大致,但是Go中switch语句后面的表达式甚至不是必须的.
注意:

  • 做花括号必须与switch同一行
  • 条件表达式不限制为常量或者整数
  • 单个case中,可以出现多个结果选项
  • 与C语言等规则相反,Go语言不需要用break退出一个case
  • 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case
  • 可以不设定switch之后的条件表达式,在此种情况下,整个switch结构与多个if…else…的逻辑作用等同

循环语句

Go中只支持for关键字,不支持while和do-while结构.
Go中for循环同样支持continue和break来控制循环,但是Go提供了一个更高级的break,可以选择中断哪一个循环.

跳转语句

goto语句被多数人反对,但是Go语言仍然支持goto关键字.

函数

函数的基本组成为:关键字func,函数名,参数列表,返回值,函数体和返回语句

函数定义

func 函数名(参数列表) (返回值) {
函数体
返回值
}
其中参数列表和返回值都需要写清楚返回值和类型,如果类型统一,那么只需要写一次即可.

不定参数

形如…type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数.这其实是一种语法糖,为了方便程序员写代码.

不定参数的传递

func myfunc(args ...int) {
    // 按原样传递
    myfunc3(args...)
    // 传递片段    
    myfunc3(args[1:]...)
}

任意类型的不定参数

例子:

func MyPrintf(args ...interface{}) {
    for _, arg := range args {
	    switch arg.(type) {
		}
	}
}

匿名函数与闭包

匿名函数

匿名函数由一个不带函数名的函数声明喝函数体组成,如下所示:

func(a, b int, z float64) bool {
    return a*b <int(z)
}

匿名函数可以直接赋值给一个变量或直接执行

f = func(a, b int, z float64) bool {
    return a*b <int(z)
}

func(ch chan int){
	ch <- ACK
} (reply_chan)  // 花括号后面跟参数列表表示函数调用

闭包

基本概念

闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不再这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义.要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及他们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)

闭包的价值

闭包的价值在于可以作为函数对象或者匿名函数

Go中的闭包
a := func() (func()) {
	var i int = 10
	return func() {
		fmt.Printf("i, j: %d, %d\n", i, j)
	}
}()

错误处理

error接口

Go语言引入了一个关于错误处理的标准模式,即error接口,该接口定义如下:

type error interface {
    Error() string
}

defer

defer关键字不管在是否出现异常,最后都会执行defer后的表达式

defer后面还可以跟匿名函数 一个代码块中可以有多个defer 但是defer执行的时候遵循先进后出的规则

panic() 和 recover()

当一个函数执行过程中调用panic()函数时,正常的函数执行流程立即终止,并且返回调用函数执行panic()函数,直到所属的goroutine中所有正在执行的函数被终止.

recover()函数用于终止错误处理流程.一般情况下,recover()函数在defer关键字的函数中确保有效地截取错误信息

参考

  • 《Go语言编程》——许式伟

猜你喜欢

转载自blog.csdn.net/Sun_White_Boy/article/details/84935521