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 = 2
fmt.Println(unsafe.Sizeof(i)) // 4
var i1 int = 2
fmt.Println(unsafe.Sizeof(i1)) // 8
var i2 float32 = 1.0
fmt.Println(unsafe.Sizeof(i2)) // 4
var i3 bool = true
fmt.Println(unsafe.Sizeof(i3)) // 1
var i4 byte = 1
fmt.Println(unsafe.Sizeof(i4)) // 1
变量
- 变量的声明格式: var <变量名称> [变量类型]
- 变量的赋值格式: <变量名称> = <值 ,表达式,函数等>
- 声明和赋值同时进行: var <变量名称> [变量类型]= <值 ,表达式,函数等>
- 分组声明格式:
var(
i int
j float32
name string
)
- 同一行声明多个变量和赋值
var a, b, c int = 1,2,3
// 或者
var a,b,c = 1,2,3
// 省略var
a,b,c := 1,2,3
- 全局变量的声明必须使用var关键词,局部变量则可以省略
var a=1
func main(){
b:=2
fmt.Println(a,b)
}
- 特殊变量下划线 ”_”
var _ = 2
// 无法使用_
- Go中不存在隐式转换,类型转换必须是显式的;
var a =1
var b = float32(a)
类型转换只能发生在两种兼容类型之间;
大写字母开头的变量是可导出的,也就是其它包可以读取的,是公用变量;
小写字母开头的就是不可导出的,是私有变量。
// pkg1
func F1(){}
func f1(){}
// main
func main(){
pkg1.F1()
//pkg1.f1() 无法访问
}
常量
显式: const identifier [type] = value 隐式: const identifier = value ( 通常叫无类型常量)
const name = "cxk"
const age int = 18
const (
habbit1 = "sing"
habbit2 = "rap"
)
常量可以使用内置表达式定义,例如: len(),unsafe.Sizeof()等 ; 常量范围目前只支持布尔型、数字型(整数型、浮点型和复数)和字符串型;
特殊常量iota
- iota在const关键字出现时将被重置为0
- const中每新增一行常量 声明将使iota计数自增1次
const a = iota
const b = iota
const (
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 := 1
b := 2
a++ // ++运算符只能这样用
println(a)
b-- // --运算符只能这样用
println(b)
控制语句
- 条件控制
a := 0
if a>=1 {
println("true")
}else if a <= 0 {
println("false")
}
- 选择语句
a := 10
switch 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)
}
// foreach
a := []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("---")
// map
aMap := 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)) // 3
println(cap(slice)) // 5
aChan := make(chan int,1)
aChan <- 1
close(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.WaitGroup
func 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:=20
var pi *int=&i // pi指向i
fmt.Println(*pi) // 读取pi所指向的内容
fmt.Println(pi == nil) // 判断是否为空
a,b :=1,2
pa := [...]*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 Setting
err := json.Unmarshal([]byte(str),&setting)
if err != nil {
fmt.Println(err)
}else {
fmt.Println(setting)
}
module
- 初始化项目
go mod init
- 输出项目依赖
go mod graph