go
- 静态类型、编译型
- 支持两种范式
- 特点
- 原生并发支持
概念
package
- 基本的分发单位、依赖关系的体现
- 每个源码文件都必须声明package
- 要生成可执行程序,必须要有main的package,并且还需要有main函数
- 同一个路径下只能存在一个package
源码文件
- 命令源码文件、库源码文件
- 测试源码文件
命令行工具
- go build 编译
- go run 编译并运行
- go get获取远程代码包
语法
- 注释
// single row/*multi row*/
- 基础结构
package main // 程序所属包import "fmt" // 导入依赖包const NAME = "cxk" // 常量定义type myInt int // 一般类型声明// 结构体声明type user struct { }// 接口声明type UserService interface { }// 入口函数func main(){ var a = "cxk" fmt.Println(a+NAME)}
import
- 不能导入源码中没有使用的package
// 另外一种语法import ( "fmt" "time")
原理
- 如果一个main导入其他包,包将被顺序导入;
- 如果导入的包中依赖其它包(包B) ,会首先导入B包,然后初始化B包中常量和变量,最后如果B包中有init ,会自动执行init() ;
- 所有包导入完成后才会对main中常量和变量进行初始化,然后执行main中的init函数(如果存在) , 最后执行main函数;
- 如果一个包被导入多次则该包只会被导入一次;
别名
- 别名操作的含义是:将导入的包命名为另- -个容易记忆的别名;
import pk "awesomeProject/pkg1"pk.F()
- 点(.)操作的含义是:点(.)标识的包导入后,调用该包中函数时可以省略前缀包名;
import . "awesomeProject/pkg1"F()
- 下划线(_ )操作的含义是:导入该包,但不导入整个包,而是执行该包中的init函数,因此无法通过包名来调用包中的其他函数。使用下划线(_ ) 操作往往是为了注册包里的引擎,让外部可以方便地使用;
import _ "awesomeProject/pkg1"
数据类型
- 数值类型,字符串类型和布尔型;
- 派生类型;
var i uint32 = 2fmt.Println(unsafe.Sizeof(i)) // 4var i1 int = 2fmt.Println(unsafe.Sizeof(i1)) // 8var i2 float32 = 1.0fmt.Println(unsafe.Sizeof(i2)) // 4var i3 bool = truefmt.Println(unsafe.Sizeof(i3)) // 1var i4 byte = 1fmt.Println(unsafe.Sizeof(i4)) // 1
变量
- 变量的声明格式: var <变量名称> [变量类型]
- 变量的赋值格式: <变量名称> = <值 ,表达式,函数等>
- 声明和赋值同时进行: var <变量名称> [变量类型]= <值 ,表达式,函数等>
- 分组声明格式:
var(i intj float32name string)
- 同一行声明多个变量和赋值
var a, b, c int = 1,2,3// 或者var a,b,c = 1,2,3// 省略vara,b,c := 1,2,3
- 全局变量的声明必须使用var关键词,局部变量则可以省略
var a=1func main(){ b:=2 fmt.Println(a,b)}
- 特殊变量下划线 ”_”
var _ = 2// 无法使用_
- Go中不存在隐式转换,类型转换必须是显式的;
var a =1var b = float32(a)
类型转换只能发生在两种兼容类型之间;
大写字母开头的变量是可导出的,也就是其它包可以读取的,是公用变量;
小写字母开头的就是不可导出的,是私有变量。
// pkg1func F1(){}func f1(){}// mainfunc main(){ pkg1.F1() //pkg1.f1() 无法访问}
常量
显式: const identifier [type] = value隐式: const identifier = value ( 通常叫无类型常量)
const name = "cxk"const age int = 18const ( habbit1 = "sing" habbit2 = "rap")
常量可以使用内置表达式定义,例如: len(),unsafe.Sizeof()等 ;常量范围目前只支持布尔型、数字型(整数型、浮点型和复数)和字符串型;
特殊常量iota
- iota在const关键字出现时将被重置为0
- const中每新增一行常量 声明将使iota计数自增1次
const a = iotaconst b = iotaconst ( c = iota d = iota)func main(){ fmt.Println(a,b) // 0 0 fmt.Println(c,d) // 0 1}
- iota常见使用法:
1)跳值使用法;
const ( c = iota _ = iota d = iota)func main(){ fmt.Println(c,d) // 0 2}
2)插队使用法;
const ( c = iota d = 3 e = iota)func main(){ fmt.Println(c,d,e) // 0 3 2}
3 )表达式隐式使用法;
const ( c = iota *2 d // 没有指定值,默认会继承之前的表达式 e)func main(){ fmt.Println(c,d,e) // 0 2 4}
4)单行使用法;
const ( a ,b = iota,iota+3 c,d)func main(){ fmt.Println(a,b,c,d) // 0 3 1 4}
运算符
a := 1b := 2a++ // ++运算符只能这样用println(a)b-- // --运算符只能这样用println(b)
控制语句
- 条件控制
a := 0if a>=1 { println("true")}else if a <= 0 { println("false")}
- 选择语句
a := 10switch a {case 1: { println("1") }case 2: { println("2") }default: { println("default") }}
- 循环语句
// 死循环for { println("run") time.Sleep(1*time.Second)}// 经典for循环for i:=1;i<10;i++ { println("run",i)}// foreacha := []string{"cxk", "jntm"}for key, value := range a { println(key, value)}
- goto
if true { goto label2}else { goto label1}label1: println("label1")label2: println("label2")
- break
a := []string{"cxk", "jntm"}for key, value := range a { println(key, value) if key == 0 { break }}
内建方法
make
// slice类似于数组slice := make([]string,3)slice[0] = "cxk"slice[1] = "cxk2"slice[2] = "cxk3"for k,v := range slice { println(k,v)}println("---")// mapaMap := make(map[string]string,3)aMap["a"]="1"aMap["b"]="2"for k,v := range aMap { println(k,v)}println("---")// channel 类似缓冲区aChan := make(chan int,3)close(aChan)
new
// 返回一个指针aMap := new(map[string]string)fmt.Println(reflect.TypeOf(aMap)) // *map[string]string
append & copy & delete
slice :=make ([]string,2)slice[0]="1"slice[1]="2"slice = append(slice,"3")fmt.Println(slice) // 1 2 3
slice1 :=make ([]string,2)slice1[0]="1"slice1[1]="2"slice2 :=make([]string,2)copy(slice2,slice1)fmt.Println(slice2) // 1 2
aMap := make(map[string]string)aMap["1"]="a"aMap["2"]="b"delete(aMap,"1")fmt.Println(aMap) // 2:b
异常
func main() { defer func() { // 异常处理 msg := recover() fmt.Println("msg:",msg) }() // 抛出异常 panic("异常")}
len && cap && close
slice := make([]int,3,5)println(len(slice)) // 3println(cap(slice)) // 5aChan := make(chan int,1)aChan <- 1close(aChan)
结构体
// 定义结构体type Person struct { Name string Age int}func main(){ var p Person // 声明结构体变量 p.Age = 18 // 结构体成员赋值 p1 := Person{Name: "cxk"} // 另外一种方式 p2 := new(Person) // 返回一个Person指针 p.Name = "cxk" fmt.Println(p)}
属性及函数
- 两种作用域,大写开头为公开,小写开头为私有
// 定义Person的一个公开成员方法func (p *Person)Say(){ fmt.Println("person say")}
组合
type Animal struct { Type string}type Dog struct { Animal // 组合animal,Dog继承Animal的属性 Name string}
并发
- 协程
func main(){ go run() go run() time.Sleep(time.Second*5)}func run(){ for i:=1;i<10;i++ { time.Sleep(time.Millisecond*2) print(i) } println()}
- 协程通讯
var chanInt = make(chan int,10)func main(){ go send() go receive() time.Sleep(5*time.Second)}func send(){ chanInt <- 1 chanInt <- 2 chanInt <- 3}func receive(){ num := <- chanInt fmt.Println(num) num = <- chanInt fmt.Println(num) num = <- chanInt fmt.Println(num)}
- 使用select
var chanInt = make(chan int,10)var chan1 = make(chan int,10)func send(){ for i:=0;i<10;i++ { chanInt <- i chan1 <- i*i }}func receive(){ for { select { case num := <- chanInt: fmt.Println(num) case num := <- chan1: fmt.Println(num) } }}
select可以随机在多个channel中取数据
- 同步
func main(){ makeFood(10) go eatFood(10) waitGroup.Wait()}var waitGroup sync.WaitGroupfunc makeFood(i int){ for j:=0;j<i;j++ { waitGroup.Add(1) fmt.Println("make food",j) }}func eatFood(i int){ for j:=0;j<i;j++ { fmt.Println("eat food",j) waitGroup.Done() // countdown }}
指针
i:=20var pi *int=&i // pi指向ifmt.Println(*pi) // 读取pi所指向的内容fmt.Println(pi == nil) // 判断是否为空a,b :=1,2pa := [...]*int{&a,&b} // 指针数组(元素为指针的数组)fmt.Println(pa)arr := [...]int{1,2,3}ap := &arr // 数组指针(指向一个数组的指针)fmt.Println(ap)
json
- 序列化
setting := Setting{Menu:"menu",Count: 15}byte,err:=json.Marshal(setting)if err!=nil { fmt.Println(err)}else { fmt.Println(string(byte))}
- tag
type Setting struct { Menu string `json:"menu"` // 指定序列后的字段名字 Count int}
- 反序列化
str := "{\"menu\":\"menu\",\"Count\":15}\n"var setting Settingerr := json.Unmarshal([]byte(str),&setting)if err != nil { fmt.Println(err)}else { fmt.Println(setting)}
module
- 初始化项目
go mod init
- 输出项目依赖
go mod graph