Go学习-入门

Go入门

  • go mod init 初始化工程

变量

  • var a,b *int 变量声明
  • bool,string,uint,byte,float,complex
  • 在go语言中所有的东西都是被初始化的 string = nil
  • 不知名类型声明 var level =1,在编译的时候会初始化类型
  • 批量格式定义
go 复制代码
var (
	a int
	b string
	c []float32
)
  • i:=1 最简单的模式 只能定义在内部
  • conn,err := net.Dial("tcp","127.0.0.1") 这样也是可以重新定义conn1,err,两个中只要有一个不同就行
  • 不想接受就是可以为匿名变量 conn,_ 下划线就是匿名变量
  • 全局变量的声明必须以var关键字开头,如果想在外部包中使用全局变量的首字母必须大写 就是在main 外部定义 var int global
  • func sum(a int,b int) int{}
  • var is bool
  • go的值比较非常严格
  • byte 就是char
  • var mystr01 string var mystr02 [5]byte = [5]byte{1,2,3,4,5}
  • 字符串长度len 中文字符串长度 utf8.RunCountInString(s)
  • 字符串拼接直接用加号就行 另外一种拼接方式
go 复制代码
//节省内存分配 提交效率
var StringBuilder bytes.Buffer
stringBuilder.WriteString(s1)
stringBuilder.WriteString(s2)
  • 直接索引对rune无效 string([]rune(mystr)[6])
  • 对中文进行遍历需要使用range的方式进行遍历
go 复制代码
for _,s:=range str{
}
  • 字符串搜索
go 复制代码
//-1 不存在 获取的是索引值 是从0开始的
postion:=strings.Index(value,"s")

类型转换

  • go语言不存在隐式类型转换所有的转换必须是显示声明的 int(value)强制转化
  • 不同类型转化会发生错误 bool => int 就是会发生错误
  • golang语言的字符串是不可变的 所以先转化为[]byte(string)[1] = 1然后再去修改其中的一位

常量

  • const name string = "nihao"
  • iota 常量生成器 第一个iota会被置为0

指针

  • %p代表指针的格式化
  • &取地址 *取内容
  • 创建指针 prt :=new(string) 创建一个字符串的指针
  • flag是用来执行命令的
  • 堆:用来存放进程中被动态分配的内存段,大小不固定
  • 栈:就是用来存放局部变量 比较快

类型别名

  • type rune = int32 这个就是别名
  • type mybool bool 这个时类型定义
  • 有什么差别呢? 在查看类型时候别名返回的就是原来的类型,但是定义返回的是当前定义的类型

关键字

  • 在go中变量推荐使用下划线表示 name_sex

字符串和其他类型的转换

go 复制代码
	//str 转int
	str := "1"
	intv, _ := strconv.Atoi(str)
	fmt.Println("%T", intv)
	//int 转str
	intv1 := 1
	strv := strconv.Itoa(intv1)
	fmt.Println("%T", strv)
	//str to float 字符串到float
	strf := "3.1415"
	stof, _ := strconv.ParseFloat(strf, 64)
	fmt.Println(stof)
	//浮点数转化为字符串
	strconv.FormatFloat()

控制台标准输入输出

  • bufio.NewReader()

数组

  • Go语言中的数组的长度是固定的
  • var arr [10]int
go 复制代码
	var arr [10]int
	fmt.Println(arr)
	for index, value := range arr {
		fmt.Println(index, value)
	}
	arr1 := [2]int{1, 2}      //推荐这样声明
	arr3 := [...]int{1, 2, 3} //自动推断
	fmt.Println(arr1, arr3)
	//数组的比较可以对同类型的数组进行比较 只有所有的值和个数相等的时候才能比较
	var arrmore [10][10]int
	fmt.Println(arrmore)
	arrmore1 := [2][2]int{{10, 1}, {1, 5}}
	fmt.Println(arrmore1)
	//多维数组要是类型相同也是可以相互赋值的 持有的是引用

切片

  • 和数组差不多,不过是长度是不确定的,每个都将数组作为底层数组,切片是引用类型,左闭右开
  • a[:] a[1:3] a[:3]
  • 声明一个切片 var name []int ,
go 复制代码
//数组的比较可以对同类型的数组进行比较 只有所有的值和个数相等的时候才能比较
	var arrmore [10][10]int
	fmt.Println(arrmore)
	arrmore1 := [2][2]int{{10, 1}, {1, 5}}
	fmt.Println(arrmore1)
	//多维数组要是类型相同也是可以相互赋值的
	var sle []int //生成空切片
	l := len(sle)
	fmt.Println(l)
	sle = append(sle, 1)
	//使用make函数生成切片  make([]Type,size,cap) size是为这个元素分配提前分配,cap下次扩充加多少个
	mkt := make([]int, 10)
	fmt.Println(mkt)
	//复制函数 coyp(目标,要复制的) //必须要同类型长度足够 返回值为个数
	arrrr := []int{10, 20, 30, 40, 50}
	arrrrc := []int{10, 2, 58, 8}
	fmt.Println(arrrr, arrrc)

map

  • 是一种无序的键值对
go 复制代码
	var mymap map[string]int //键值对
	mymap2 := map[string]int{"nihao": 1, "buhao": 2}
	fmt.Println(mymap, mymap2)
	fmt.Println(mymap["nihao"])
	//make 创建
	mmap := make(map[string]string, 10) //虽然会自动加1 但是最好先初始一下
	fmt.Println(mmap)
	//一个切片对应多个值
	mms := make(map[string][]int)
	mms2 := make(map[string]*[]int)
	mms["name"] = []int{1, 2, 3}
	mms["555"] = []int{5, 2, 3}

	fmt.Println(mms, mms2)
	for k, v := range mms {
		fmt.Println(k, v)
	}
	//清空map 重新生成一个 线程不安全的
	//线程安全map sync.Map
	var mysyncmap sync.Map
	mysyncmap.Store("key", "value")
	mysyncmap.Store("key2", "value2")
	mysyncmap.Load("key2")
	mysyncmap.Range(func(key, value interface{}) bool {
		fmt.Println(key, value)
		return true
	})

nil

  • nil 是不能进行比较 nil==nil
  • 不同的值nil对应的大小是不一样的

new 和make

if else

go 复制代码
if 1 == 1 {
		fmt.Println("true")
	}
	//特殊写法
	if x:=100;x>10 {
		fmt.Println("x")
		//这个x是块级作用域
	}

for

go 复制代码
	for i := 0; i < 20; i++ {
		fmt.Println(i)
	}
	//死循环
for{
	break
		
	}
	//直接写条件相当于while
for a>100{
		goto bTag
	}
//标签
break bTag:

for range

go 复制代码
	forragnge := make(map[string]string)
	forragnge["a"] = "a"
	forragnge["b"] = "b"
	for i, v := range forragnge {
		fmt.Println(i, v)
	}

switch

  • 每个最后是携带break的
go 复制代码
	a := 1
	switch a {
	case 1:
		fmt.Println("1")
	case 2, 3, 4:
		fmt.Println("2,3,4")
	}
	//LIANG
	switch  {
	case a==2:
		fmt.Println("a==2")
		fallthrough //这个就是可以往下走 无论成功与否
	case a==3:
		fmt.Println("a==3")
	}

goto

  • 标签 name:
  • 使用 goto name
  • 使用goto处理错误

break continue

  • break 也可以跳出一个代码块 也可以和goto一样使用
  • continue 就是跳过本次 也可以和goto一样使用

函数

  • 函数作为一等公民 可以传递
go 复制代码
func max(n1,n2 int32) (int32,string) {
	if n1 > n2 {
		return n1
	}
	return n2,"nihao"
}

func funarg(fn func() int) int32{
	
	return int32(fn())
	
}
  • 返回值,支持对返回值的命名
go 复制代码
func funcr() (ni string, hao string) {
	ni = "hello"
	hao = "world"
	return //对自动返回名字
}
  • 参数
  • map,slice,chan,指针,interface默认是引用的方式进行传递
  • 多个参数 args 本质上就是一个切片
  • 返回一个闭包 那么里面的变量的值都是被持有的 那么里面的值每一个次都是不会被清空的
  • 延迟调用 defer
  • defer 不能直接执行 要放到匿名函数中 不然就是会出现问题
  • defer 在闭包内使用到的变量 会保存上下文用到的变量

错误处理

  • panic 遇到panic() ,就会终止 然后执行defer语句 再报告异常信息 然后推出gorotine 如果再defer中使用了revocer()函数,就会捕获醋无哦信息,是该错误信息终止报告
  • recover() 可以捕获到异常
  • 延时调用中的错误,可以被后续的延时调用捕获,单只可以捕获最后一个
go 复制代码
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	panic("error!")

结构体

go 复制代码
	type my_struct struct {
		name string
		id   int
		x    int
		y    int
	}
	var mys1 my_struct
	mys1.x = 1
	mys1.y = 2
	mys := my_struct{id: 1, name: "nihao", x: 1, y: 2}
	fmt.Println(mys)
	//使用new进行实例化
	ins := new(my_struct)
	ins.id = 1
  • 可以使用取地址符号进行实列话 &Type{}

  • 接收器
go 复制代码
type bag struct {
	name  string
	goods []string
}

func (b *bag) GetGoods() string {//命名建议使用首字符
	return b.goods[0]
}
  • 想比与继承更适合组合
go 复制代码
type bag struct {
	name  string

}
type Big struct {
	bag
}
//组合可以直接调用 bag中的方法等
bb := Big{bag{"11"}}

接口

go 复制代码
type AnimalIF interface {
	Sleep()
	GetName() string
	SetName(string)
}
  • 当你的struct去实现了接口就是实现了所有的方法 就相当于你实现了这个接口 这个就是非侵入式
  • 一个类型可以实现多个接口
  • 空接口 var int interface{}
  • 断言
go 复制代码
	v, ok := ink.(int) //类型断言
	fmt.Println(v, ok) //第一个参数值,第二个参数状态

I/O操作

Reader

go 复制代码
reader := strings.NewReader("askjdfk sadfkjsad fasdfjk sdf")
	p := make([]byte, 8)
	for {
		n, err := reader.Read(p)
		if err == io.EOF {
			fmt.Println("读完了",n)
			break
		}
		fmt.Println(p[:n])
	}

文件操作api

go 复制代码
	//创建文件写入
	create, _ := os.Create("test.txt")
	n, err := create.Write([]byte("hello world"))
	if err != nil {
		return
	}
	fmt.Println(n)
	create.Close()
	//读取文件写入
	var rr [32]byte
	rr := make([]byte, 32)
	open, _ := os.Open("test.txt")
	open.Read(rr) //这里面要求传入的是切片 注意注意!!!!
	fmt.Println(rr)
	//文件删除
	os.Remove("test.txt")

bufio 带缓冲区的文件读写

go 复制代码
	file, _ := os.OpenFile("test.txt", os.O_APPEND, 0777)
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++ {
		builder := strings.Builder{}
		builder.WriteString("hello")
		builder.WriteString(strconv.Itoa(i))
		builder.WriteString("\n\r")
		s := builder.String()
		writer.WriteString(s)
	}
	writer.Flush()
	reader:= bufio.NewReader(file)
	for{
		line, _, err := reader.ReadLine()
	}

ioutil

  • 所用的包被代替、
go 复制代码
	//读取文件所有的内容
	file, err := os.ReadFile("test.txt")
	if err != nil {
	}
	fmt.Println(string(file))
	//讲内容完全写入文件
	os.WriteFile("test2.txt", []byte("sdafasdf"), 0777)

	readFile, err := os.ReadFile("test2.txt")
	if err != nil {
	}
	fmt.Println(string(readFile))

goroutine

go 复制代码
func test(){
	fmt.Println("test")
}
func main(){
	go test()//这个携程是依赖于main goroutine
	fmt.Println("main groutine") 

}

runtime包

  • runtime.Gosched() 再次重新分配一下任务
  • runtime.Goexit() 退出携程
  • runtime.GOMAXPROCES(1) 设置核心数

channel

  • var ch chan int 创建一个int型的通道
  • 声明完成需要make才能使用 make(chan 元素类型,[缓冲区大小])
  • ch:=make(chan int,10)
  • 操作 :发送,接受,关闭
  • 发送和接受使用 <- 这个符号
  • 发送 ch<-10 把10发送金桔
  • 接受 x:=<-ch
  • 关闭通道 close(ch) ,通道可以被垃圾回收机制给回收,对一个关闭的通道发送数据就会导致panic
  • 无缓冲的channel
    无缓冲的通道必须要存在接受者才能发送 无缓冲会阻塞
go 复制代码
func rec(ch chan int){
	temp:=<-chan
	fmt.PrintLn(temp)
}
func main(){
	ch:=make(chan int)
	rec(ch)
	ch<-10
	fmt.PrintLn("发送者")
}
  • 有缓冲通道
go 复制代码
func main(){
	ch:=make(chan int,1)
	ch<-1 //可以先放入一个
}
  • 如何判断通道已经被关闭了 使用for range 就可以判断channel是否关闭 关闭了for range就是退出循环了
  • 单向通道
go 复制代码
var dan chan<- int = make(chan int)
func counter(out chan<- int){
	//这个代表的意思是只能往里面去放入
	out<-10
}
func chu(in <-chan int){
	//这个就是只能出
	temp:=<-in
}
  • select 可以同时相应多个通道的操作
  • select 反正是看谁先
go 复制代码
select{
	case <-chan1:
		//如果从chan1读取到数据
	case chan1<-:
		//如果成功写入数据
	default:
		//都没有成功	
}
  • 判断channel是否慢
go 复制代码
func test(ch chan int){
	select{
		case ch<- 1:
			fmt.p("写")
		default:
			//到这边执行就是满了
	}

}

并发安全和锁

  • 互斥锁 var lock sync.Mutex
  • lock.Lock() lock.Unlock() 同一时间只能够保证有一个进入临界区
  • 读写互斥锁 当一个goroutine获得读锁 其他来也可以获得读 不可以获得写 当加上一个写锁 读和写都无法执行 sync.RWMutex
  • 加锁涉及到内核态的转变 消耗比较高
  • 基本数据类型 可以使用原子操作 sync/atomic atomic

Golang 调度器

Go的协程

  • g携程 只占几kb
  • m线程
  • p管理本地的队列
  • M线程通过P 去操作G ,p会认为是cpu操作的核心数,GOMAXPROCES个数
  • 线程想要运行就要先从p去获取携程

调度策略

网络编程

socket

  • 就是封装了tcp/ip协议 只要调用socket就可以轻松实现tcp ip编程

TCP编程

  • 面向连接,可靠的,基于字节流的通讯协议,因为是面向连接的,数据像流水一样传输,会存在黏包问题
  • 使用net包 net.Listen("tcp","127.0.0.1:20000")
  • net包也可以作为服务器的客户端 发起一个连接

UDP编程

  • 实时性比较好
  • net.ListenUDP("udp",&net.UDPAddr{
    IP:net.IPv4(0,0,0,0)//监听所有
    Port:3000,
    })

HTTP编程

  • 具体使用百度

websocket

MYSQL

go 复制代码
func init(){
	//在执行main方法前会执行init方法
	sql.Open("mysql","root:root@tcp(localhost:3306)/go_table")
	DB.Exec("insert into user() values(?,?,?)",username,sex,e)
	rows,err = DB.Query("select * form user where id = ?",id)
	for rows.Next(){
		
	}
	//事务
	con,err:=DB.Begin()
	_ := Db.commit()
	_ := Db.rollback()
}

redis

Go泛型

go 复制代码
func IntOrFloats[K comparable,V int64|float64](m map[K]V)V{
	//前面再中括号中去定义类型,然后后面使用, 使用前面的名字都行,返回值和参数都可以是泛型 里面的变量声明也可以使用KV去代替为泛型
}
//泛型的定义
type fanxing interface{//定义一个类型约束
	int | float64 |string
}
//这边去调用泛型
func IntOrFloats[K comparable,V fanxing](m map[K]V)V{
	//前面再中括号中去定义类型,然后后面使用, 使用前面的名字都行,返回值和参数都可以是泛型 里面的变量声明也可以使用KV去代替为泛型
}

多模块工作目录

  • 再包含两个项目的大目录下 go work init ./fly-falsh 随便那个都行
  • go work use ./common 两个都加入

模糊测试

  • go test
相关推荐
JenKinJia6 分钟前
Windows10配置C++版本的Kafka,并进行发布和订阅测试
开发语言·c++
煤炭里de黑猫8 分钟前
Lua C API :lua_insert 函数详解
开发语言·lua
笨鸟笃行10 分钟前
爬虫第七篇数据爬取及解析
开发语言·爬虫·python
编程乐趣11 分钟前
一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略来了!
开发语言·c#
java1234_小锋16 分钟前
一周学会Flask3 Python Web开发-response响应格式
开发语言·python·flask·flask3
Jelena1577958579216 分钟前
使用Java爬虫获取1688 item_get_company 接口的公司档案信息
java·开发语言·爬虫
java1234_小锋18 分钟前
一周学会Flask3 Python Web开发-flask3模块化blueprint配置
开发语言·python·flask·flask3
我是苏苏42 分钟前
C#基础:使用Linq进行简单去重处理(DinstinctBy/反射)
开发语言·c#·linq
小小码农(找工作版)44 分钟前
C#前端开发面试题
开发语言·c#
不爱学英文的码字机器1 小时前
Python爬虫实战:从零到一构建数据采集系统
开发语言·爬虫·python