本文基于golang1.12.5

前提知识

xxx.goxxx.go

代码规范

golang对代码规范要求十分严格,不规范代码会产生各种问题。

  • 函数的第一个括号必须和函数名位于同一行
  • if语句的第一个括号必须与if位于同一行
  • else语句必须与其对应的if的上一个右括号以及自身左括号位于同一行
  • switch语句的右括号必须与switch在同一行

常用的包

fmt

golang关键字

int default break func interface select case defer go map
struct chan else goto package switch const fallthrough if
range type continue for import return var

内建常量

true falseiotanil

内建类型

int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error

内建函数

make len cap new append copy close delete
complex real imag
panic recover
函数名说明
len、caplen用于返回某个类型的长度或数量(字符串、数组、切片、map、管道);cap用于返回某个类型的最大容量(只可用于切片和map)
new、makenew和make都用于内存分配:new用于值类型和用户定义的类型,make用于内置类型(切片、map、管道)
copy、appendcopy用于复制切片;append用于连接切片
panic、recover两者均用于错误处理机制;panic类似于C语言中的perror
print、println底层打印函数
complex、read、imagcomplex用于创建复数;read用于提出复数的实部;imag用于提取复数的虚部

变量

定义变量

package main
import "fmt"
func main() {
    var a int	//声明的变量必须使用,否则会产生错误
    a = 1	//变量赋值
    fmt.Println(a)
    var b, c int
    b, c = 3, 4
    fmt.Println(b, c)
}

//使用var关键字声明变量的初始化方式:
//1.声明之后采用赋值
//2.var 变量名 变量类型 = 变量初始值
package main
import "fmt"
func main() {
    a := 1	//定义变量+初始化
    b, c := 3, 3.1415
    fmt.Println(a)
    fmt.Println(b, c)
}
package main
import "fmt"
func main() {
    var a = 1	//定义变量+初始化
    var (
        b = 3
        c = 3.1415
    )
    fmt.Println(a)
    fmt.Println(b, c)
}
:=

交换两个变量的值

package main
import "fmt"
func main() {
    a := 3
    b := 5
    a, b = b, a
    fmt.Println(a, b)
}

匿名变量

_

常量

声明常量

package main
import "fmt"
func main() {
    const a int = 1	//声明常量必须进行初始化
    fmt.Println(a)
}
package main
import "fmt"
func main() {
    const a = 1	//常量推导类型使用=,与变量不同
    fmt.Println(a)
}

数据类型

内建类型

自定义类型

数组
var arr1 [5]int	//具有5个int元素的数组,未进行初始化,元素默认为零值
var arr2 [5]int{1, 2, 3, 4, 5}	//定义并直接初始化
切片
var sic1 []int	//声明含有多个未知元素的切片
var sic2 []int{}	//声明空切片
结构体声明
package main
import "fmt"
type student struct {
    var id int32
    var name string
}	//声明一个结构体
func main() {
    var ahaoo student	//创建结构体对象
    ahaoo.id = 1
    ahaoo.name = ahao
    fmt.Println(ahaoo.id, ahaoo.name)
    
    var nar student = {2, "nar"}
    fmt.Println(nar.id, nar.name)
}
枚举声明
package main
import "fmt"
const (
	r = iota	//0
	s = iota	//1
	t = iota	//2
	)

const (
    u = iota	//0
    v			//1
    w			//2
)

const (
    u1 = iota	//0
    v1, w1, x1 = iota, iota, iota	//1, 1, 1
)
func main() {
    fmt.Println(r)   
}

指针

&
//普通指针的声明
var 指针名 *指针类型
//函数指针的声明方式
//1.推导类型
func test() {
    //TODO
}
funcptr := test

//var声明
var 函数指针名 func(参数列表)

类型转换

要转换的数据类型(变量名)
  • bool类型不能转换为整型,整型也不能转换为bool类型,这种不能转换的类型叫做不兼容类型。

类型别名

type 类型别名 类型原名

逻辑语句

if语句

if
  • 左括号必须和if在同一行
if/else
  • else必须和if的右括号以及自己的左括号在同一行
if/else if/…/else
  • else if必须和上一个右括号以及自己的左括号在同一行

for循环

基本格式
for 初始条件; 判断条件; 条件变换 {
    //TODO
}
range关键字的使用
  • 作用:迭代遍历切片/数组中的每一个元素,默认有两个返回值,第一个为元素下标,第二个为元素数据
for k, v := range array {
    //k为array中元素的下标
    //v为array中元素的数据
}

for k := range array {
    //此时第二个返回值默认丢弃
}

for _, i := range array {
    //此时第一个参数默认丢弃
}

switch语句

  • golang保留break关键字,在switch语句中如果不写则默认添加
    • break可用于for/switch/select
    • continue只可以用于for
  • case后面可以跟多个条件
//首先声明变量
var num1 int = 1
switch num1 {
    case 1:
    	//...
    case 2:
    	//...
    case 3, 4, 5:
    	//...
    ...
    default:
    	//...
}

//直接使用初始化语句
switch num2 := 1; num1 {
    case 1:
    	//...
    case 2:
    	//...
    ...
    default:
    	//...
}

//switch后面可以不添加参数
var num int = 0
switch {
    case num > 90:
    	//...
    case num < 90:
    	//...
    default:
    	//...
}

函数

函数定义的格式

func 函数名(参数列表)(返回值变量名 返回值类型, 返回值变量名, 返回值类型...) {
    //函数体
}

func

变长参数列表

func Func(...int) {
    //TODO
}
//变长参数列表传递的参数类似于该类型的slice,可使用for循环迭代

defer关键字

derfer

golang并发

go 函数名

golang面向对象

golang中没有类,但是它支持struct,struct是用户自定义类型(含方法),可以像其他语言中的类一样使用

定义struct成员函数

(形式对象 结构体名)
//模板
func (形式对象 结构体名) 函数名(参数列表)(返回值列表) {
    //
}

嵌入

可以将一个匿名的类型嵌入彼此,如果将一个匿名的struct A嵌入另一个struct B,则A的接口也可以通过B对象来进行调用,但是A对象只能调用A自己的函数

//例子
package main
import ."fmt"

type student struct {
    name string
    id int32
    class
}

type class struct {
    
}

//student的成员函数
func (st student) GetName()string {
    return st.name
}

//class的成员函数
func (cl class) FuncTest()string {
    return "hello this is class"
}
func main() {
    var st student
    var cl class
    st.name = "ahao"
    st.id = 1
    Println(st.GetName())	//打印"ahao"
    Println(st.FuncTest())	//打印"hello this is class"
    
    Println(cl.GetName())	//编译报错
    Println(cl.FuncTest())	//打印"hello this is class"
}

接口

接口就是定义出一个类似于函数的集合,该集合中存在很多未进行定义的函数,当实现一个结构体时并且将该接口中的函数全部实现时,就成为结构体实现了该接口,体现了golang的多态性

package main
import "fmt"
type Itfe interface {
    Func1()
    Func2()
    Func3()
}

type student struct {
    
}

func (st student) Func1() string {
    return "实现了Func1()"
}

func (st student) Func2() string {
    return "实现Func2()"
}

func (st student) Func3() string {
    return "实现Func3()"
}

func main() {
    var st student
    st.name = "ahao"
    st.id = 1
    st.Func1()	//打印"实现了Func1()"
    st.Func2()	//打印"实现了Func2()"
    st.Func3()	//打印"实现了Func3()"
}

接口和结构体的关系
  • 一个接口类型的对象可以作为函数的参数来接收实现了该接口的结构体对象
  • 如果一个接口实现了某一个接口中的所有的方法,那么就可以认为这个接口实现了该接口,如果一个结构体实现了某一个接口,就说明这个结构体对象可以被参数为该接口类型的对象接收,当在函数内部通过该接口使用接口中的某一个方法时,会自动匹配对应结构体所实现的方法
  • //接口与指针TODO
接口的类型判断
func IntFunc(INTERFACE_OBJ INTERFACE_TYPE) {
    switch INTERFACE_OBJ.(type) {
        case STRUCT_TYPE1:
        	//DOSOMETHING
        case STRUCT_TYPE2:
        	//DOSOMETHING
        ...
        default:
        	//DOSOMETHING
    }
}

传入的STRUCT_TYPE不需要使用 " " 标注

  • 接口可以通过上述方式判断传入的结构体类型
空接口
  • 每一种类型都能匹配到空接口,也就是说可以使用空接口的作为函数的参数来接收任何类型的对象
//将空接口转换为INTERFACE_TYPE类型接口并进行INTERFACE_MOTHOD方法调用
func IntFunc(INTERFACE_OBJ interface{}) RETURN_TYPE {
    INTERFACE_OBJ.(INTERFACE_TYPE).INTERFACE_MOTHOD
}

封装

  • golang在包级别进行封装,以小写字母开头的函数仅在当前包中有效

特殊语法

package main
import ."fmt"
func main() {
    Println("hello world")
}