go语言编程 要点总结(二)面向过程编程

变量

变量声明

var 变量名 变量类型

变量初始化

var v1 int = 10

var v2 = 10

v3 := 10

出现在冒号左侧的不应该是被声明过的变量,而且这种简短声明只能出现在函数中

变量赋值

可以采用多重赋值 i, j = x, y

匿名变量

函数返回多个值,如果值想获得其中的某些可以使用 __, __, nickname := GetName()


常量

字面常量

硬编码的常量,不用像c语言一样在末尾加上L来区别是int还是long,go中字面常量是无类型的,只要这个常量在相应类型值域范围内,就可作为该类型常量

常量定义

通过const关键字来定义

也可以是无类型的

编译期确定,所以右值不能是执行期才确定值的表达式

预定义常量

true,false,iota

itoa在每一个const关键字出现时被置为0,下一个const出现之前,每出现一次iota,其代表的数字会自动加1

枚举

通过const后紧跟一对圆括号定义一组常量,而没有关键字enum

const (

Sunday = iota

Monday

...

)

同Go语言的其他符号一样,以大写字母开头的常量在包外可见

类型

基础类型

  • 布尔类型 bool
  • 整形 int8 byte int16 int uint unitptr等
  • 浮点类型 float32,float64
  • 复数类型 complex64 complex128
  • 字符串 string
  • 字符类型 rune
  • 错误类型 eror

复合类型

  • 指针
  • 数组
  • 切片
  • 字典
  • 通道
  • 结构体
  • 接口

布尔

不支持其他类型赋值,不能自动或强制类型转换

整型

  • int uint uintptr这三个是平台相关的
  • int和int32是不同类型,编译器不会自动转换,可以强制类型转换
  • 不同类型的值不能进行比较
  • 但是各种类型的整型都可以与字面常量比较
  • 为运算中的取反,在c中使用~,在go中使用^
  • float32等价与c中float,float64等价与c中的double
  • 没有指定类型时浮点数被自动推导为float64
  • 浮点数的比较不能用==,这可能导致不稳定结果,使用math.Fdim函数来进行比较

复数类型

  • complex64由两个float32构成
  • complex128由两个float64构成
  • 不指定类型,而推导出来的是complex128
  • value1 = 3.2 + 12i 这样就可以表示一个复数
  • 也可以用complex(3.2, 12)来表示一个复数
  • 使用内置函数real(z)获取实部,使用imag(z)获取虚部

字符串

c/c++中不存在原生字符串,而是使用字符数组,通过字符指针来传递

var str1 string声明一个字符串

可以像数组一样用下标访问,但是初始化之后的字符串不能修改

字符串中包含非ASNI的字符,比如中文,则必须把源码保存为UTF-8格式

连接操作 x + y

获取长度 len(s)

取字符 s[i]

for i : =0; i < n; i++ {

} 以字节数组的方式遍历

for i, ch := range str {

} 以unicode字符遍历,此时ch类型为rune

声明多行字符串时使用"`",它没有字符转义,换行也将输出

字符类型

byte代表utf-8中单个字节,rune代表unicode中单个字符 出于简化的考虑,多少api假设字符串为utf-8编码,使用unicode的较少

数组

[2*N]struct {x, y int32} 类型数组

[1000]*float64 指针数组

[3][5]二维数组

数组长度定义后不可修改,声明时可以使用常量或者常量表达式

可以使用...省略号声明一个数组,go语言会自动根据元素个数计算长度,但是中括号不能为空,那样就是slice了

len()获取长度

可以通过下标访问

也可以通过for i, v := range array {} 的方式访问

数组是一个值类型,传递参数时会发生一次拷贝,函数中使用的也是副本

数组切片

三组切片的数据结构包含三个变量:一个指向原生数组的指针,数组切片中的元素个数,切片已分配的存储空间

slice并不是真正的动态数组,而是一个引用类型

基于数据创建切片 myArrary[first:last],基于数组全部创建切片 myArray[:]

直接创建 mySlice1 := make([]int, 5, 10) 创建初始元素个数为5,元素初始值 0,并预留10个存储空间

mySlice3 := [int{1,2,3,4,5}] 直接初始化5个元素的数组切片,会有一个匿名的数组被创建

for i := 0; i < len(myArray); i++ 逐一遍历

或者使用range关键字 for i, v := range mySlice 遍历

cap() 返回切片空间大小, len()返回元素个数

mySlice = append(mySlice, 1,2,3) 尾部追加,并生成新的切片

mySlice = append(mySlice, mySlice2...) 省略号是必须的,append语义是从第二个参数开始是追加的元素,省略号的作用是把 mySlice2所有元素打散传入

newSlice := oldSlice[:] 基于oldSlice创建新的splice 选择的范围不能超过oldslice的cap()值,超过len的部分填充为0

通过copy来复制一个slice到另一个slice,两个不一样大小,以较小的元素个数进行复制

append的函数会改变slice所引用的数组内容,从而影响引用同一数组的其他slice。但当slice中没有剩余空间时,此时将动态分配新的数组空间。返回的slice数组指针指向这个空间,而原数组的内容将保持不变,其他引用此数组的slice不受影响。

map

声明一个map :var 变量名 map[key类型] value类型,这种声明方式需要在使用之前通过make初始化

map的key可以是所有完全定义了==或者!=操作的类型

可以通过make动态创建 myMap = make(map[key类型] value类型)

创建时初始化 myMap = map[string] PersonInfo { "1234" : PersonInfo{}, }

myMap["1234"] = PersonInfo{} 赋值

元素删除 delete(myMap, "1234") 元素不存在不会有什么问题

value, ok := myMap["1234"]

if ok {

} 这种方式进行查找

map是无序的,每次打印的map都会不一样,,只能通过key获取,不能通过index获取

map长度是不固定的,和slice一样,也是引用类型

len函数返回map拥有的key的数量

make和new的区别

make只能创建slice、map和channel,并且返回一个有 初始值(非零)的T类型,而不是*T。

new分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值。

这是因为指向数据结构的引用在使用前必须被初始化,例如slice使用前必须初始化他引用的数组。

问题:通过下标返回的值是拷贝,还是引用?


流程控制

  • 条件语句 if、 else 和else if
  • 选择语句 switch、case和select
  • 循环语句 for和range
  • 跳转语句 goto

条件语句

条件不需要小括号

无论语句体内有几条语句,花括号是必须的

左花括号必须与if或else同一行

if之后,条件语句之前,可以添加变量初始化语句,使用分号(;) 分割

在有返回值的函数中,不允许在if else中return,go编译器找不到终止该函数的return语句

错误的例子:

func example(x int) int {

if x == 0 {

return 5

} else{

return x

}

}

选择语句

左花括号必须和switch同一行

条件表达式不限制为常量或者整数

单个case中,恶意出现多个结果选项

不需要break来明确退出一个case

只有在case中明确添加fallthrough才会继续执行下一个case

可以不设定switch之后的表达式,整个switch和多个if else的逻辑作用相同

循环语句

左花括号必须和for同一行

可以在条件表达式中初始化变量或赋值,多个变量赋值时,只允许使用平行赋值的方式(i,j,k := 1, 2, 3而不是i := 1, j := 2, k := 3)

支持continue和break, break有更高级的用法,可以决定跳出哪曾循环

跳转语句

goto 跳转到某个标签

函数

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

参数列表和返回值中,多个变量类型相同可以合并,例如func Add(a,b int)

通过import导入函数所在的包,小写字母开头的函数只在本包中可见,大写字母开头的函数才能被其他包使用

通过(...type) 传递不定参数,通过for _, arg := range args 来提取不定参数

函数中调用了其他不定参数的函数,可以原样传递参数,也可以使用切片

func myfunc(args ...int) {

myfunc3(args ...)

myfunc3(args[1:]...)

}

要传递任意类型的不定参数,只要将之前的type替换为interface{}

func Printf(format string, args ...interface{}) { }

通过arg.(type)获取参数的类型:

func MyPrintf(args ...interface{}) {

for _, arg := range args {

switch arg.(type) {

case int:

case string:

case int64:

default:

}

}

}

多返回值,返回值可以命名,在函数开始的时候初始化为空,在return不带任何参数时,会返回对应的返回值变量的值(类似于传出参数),多个返回值之间用“,”分割,如果函数是首字母大写的,那么建议命名返回值变量,这样有利于生成我文档

传递指针,注意string、slice、map这三种类型的实现类似指针,可以直接传递,但函数如果修改slice长度,则仍需传递slice指针

不关注某个返回值,可以使用下划线来跳过这个返回值

函数可以通过type typeName func(input intputType...)(resutlt resultType)的方式来定义类型

匿名函数可以像变量一样传递,

匿名函数也可以直接调用,在函数体最后的右花括号后面紧跟参数列表

闭包

基本概念:闭包是可以包含自由变量的代码快,这些变量不再这个代码快内或者任何全局上下文中定义,而在定义代码快的环境中定义。要执行的代码快(由于自由变量包含在代码快中,所以这些自由变量以及她们引用的对象没有

被释放)为自由变量提供绑定的计算环境

价值:函数作为对象,保存在变量中,通过参数传递给其他函数

我的理解,类似与C++中的仿函数对象,只是不需要命名,在外部函数中定义变量,调用外部函数返回内部函数,内部函数访问了外部函数中定义的变量,因为有引用所以不能被回收,


错误处理

error接口

type error interface {

Error() string

}

自定义error类型

type PathError struct {

Op string

Path string

Err error

}

实现Error方法

func (e *PathError) Error() string {

return e.Op + " " + e.Path + ": " + e.Err.Error()

}

defer 语句遵循先进后出的原则,最后定义的defer先被执行

func panic(interface()) 正常流程终止,执行defer语句,执行完毕后返回到调用函数,并逐层向上执行panic,直至所属goroutine中所有正在执行的含数据终止

func recover() interface() 用于终止错误处理流程,一般应该在defer中调用,截取错误处理流程。在未发生一场的goroutine中明确调用回复过程,会导致该gorutinue所属的进程打印影厂信息后直接退出

panic作为最后的手段,代码中应该没有或者少有panic


mian和init函数

init函数可用于所有package,main只能用于package main

建议每个package仅使用一个init函数,尽管可以使用多个,但是从可读性角度来说使用一个i

init和main由go自动调用

init是可选的,但是main是必须的

程序初始化和执行起始于main包,编译时依次导入依赖包,并初始化包级常量和变量,调用包的init函数,每个包之后被导入一次,等所有导入的包都加载完毕,初始化main包中的常量和变量,调用main的init函数,最后执行main函数


import

可以使用相对路径和绝对路径,绝对路径从gopath/src之后的路径开始

点操作

import (

. "fmt"

)

这种方式导入包,使用时可以省略包名

别名操作

import (

f "fmt"

)

使用时可以用别名代替包名

_操作

import (

_ "githup.com/ziutek/mymysql/godrv"

)

引入该包,不直接使用包里的函数,而是调用了该包的init函数

你可能感兴趣的:(程序设计,golang)