当前位置: 首页 > article >正文

Go学习-入门

Go入门

  • go mod init 初始化工程

变量

  • var a,b *int 变量声明
  • bool,string,uint,byte,float,complex
  • 在go语言中所有的东西都是被初始化的 string = nil
  • 不知名类型声明 var level =1,在编译的时候会初始化类型
  • 批量格式定义
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)
  • 字符串拼接直接用加号就行 另外一种拼接方式
//节省内存分配 提交效率
var StringBuilder bytes.Buffer
stringBuilder.WriteString(s1)
stringBuilder.WriteString(s2)
  • 直接索引对rune无效 string([]rune(mystr)[6])
  • 对中文进行遍历需要使用range的方式进行遍历
for _,s:=range str{
}
  • 字符串搜索
//-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

字符串和其他类型的转换

	//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
	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 ,
//数组的比较可以对同类型的数组进行比较 只有所有的值和个数相等的时候才能比较
	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

  • 是一种无序的键值对
	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

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

for

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

for range

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

switch

  • 每个最后是携带break的
	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一样使用

函数

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

func funarg(fn func() int) int32{
	
	return int32(fn())
	
}
  • 返回值,支持对返回值的命名
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() 可以捕获到异常
  • 延时调用中的错误,可以被后续的延时调用捕获,单只可以捕获最后一个
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	panic("error!")

结构体

	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{}

  • 接收器
type bag struct {
	name  string
	goods []string
}

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

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

接口

type AnimalIF interface {
	Sleep()
	GetName() string
	SetName(string)
}

在这里插入图片描述

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

I/O操作

Reader

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

	//创建文件写入
	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 带缓冲区的文件读写

在这里插入图片描述

	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

  • 所用的包被代替、
	//读取文件所有的内容
	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

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
    无缓冲的通道必须要存在接受者才能发送 无缓冲会阻塞
func rec(ch chan int){
	temp:=<-chan
	fmt.PrintLn(temp)
}
func main(){
	ch:=make(chan int)
	rec(ch)
	ch<-10
	fmt.PrintLn("发送者")
}
  • 有缓冲通道
func main(){
	ch:=make(chan int,1)
	ch<-1 //可以先放入一个
}
  • 如何判断通道已经被关闭了 使用for range 就可以判断channel是否关闭 关闭了for range就是退出循环了
  • 单向通道
var dan chan<- int = make(chan int)
func counter(out chan<- int){
	//这个代表的意思是只能往里面去放入
	out<-10
}
func chu(in <-chan int){
	//这个就是只能出
	temp:=<-in
}
  • select 可以同时相应多个通道的操作
  • select 反正是看谁先
select{
	case <-chan1:
		//如果从chan1读取到数据
	case chan1<-:
		//如果成功写入数据
	default:
		//都没有成功	
}

  • 判断channel是否慢
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

  • 需要安装第三方包
  • go get -u -v github.com/gorilla/websocket
  • 所有文件要一起运行
  • https://blog.csdn.net/qq_30614345/article/details/140083133

MYSQL

  • 引入mysql驱动
  • _ “github.com/go-sql-driver/mysql”
  • 在传递值的时候只有指针、切片、映射、通道和接口是默认传递地址的
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

  • “github.com/go-redis/redis/v8”

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

http://www.kler.cn/a/555374.html

相关文章:

  • 常用电脑,护眼软件推荐 f.lux 3400K | 撰写论文 paper
  • 服务器数据迁移某个目录下的所有文件到另一台服务器
  • Ubuntu上查看端口被哪个进程占用了
  • 如何才能写出好的prompt?
  • 如何使用springboot项目如何实现小程序里面商品的浏览记录功能案例
  • Qt5 C++ TcpSocket 如何判断是服务主动断开tcp socket连接?
  • QPainter绘制3D 饼状图
  • 前端开发中的贪心算法实践:以最小成本解决实际问题
  • 自由学习记录(36)
  • C语言之typedef
  • MySQL分库分表之ShardingSphere实战
  • 【Spring详解四】自定义标签的解析
  • EasyExcel的简单使用
  • 网络缓存加速技术解析:从诞生到演进
  • Spring Cloud LoadBalancer 负载均衡
  • 自然语言处理:第九十二章 chatBI 经验(转载)
  • 【DeepSeek】如何将DeepSeek部署到本地?如何给本地 LLM 提供UI界面?CherryStudio 的使用
  • 对CSS了解哪些?
  • Lab12_ Blind SQL injection with conditional errors
  • MariaDB10创建用户并授权