day 1 将go基础知识复习一下

本文章主要是写自己在做这个项目时候遇到的一些困难,如果都是做这个项目的(后端),可以看看

这个是项目网址

gin-vue-admin : https://github.com/flipped-aurora/gin-vue-admin

在此表示对大神奇淼的敬佩

首先,我们需要去下载一个cnpm的一个东西

我是看这个博客,写的贼好

npm和cnpm(windows)安装步骤_安装cnpm-CSDN博客

然后就去vs里面执行了,我还以为没执行成功,把终端输出的东西给chatgpt看了一下,显示成功了

然后我进入了这个server项目嘛,但是之前的go感觉有些要补一下,就先开始了视频教程里面的golang教程(选择性),学语言就是这样的,学了又忘

学习就是一个重复的过程(在做项目的时候有时候会对自己产生怀疑,呜呜呜)

回忆一下

一定要以go.mod为根目录

var a string ="hello 2002"
//关键字 变量名 变量类型 = 变量值
/*
关键字不能作为变量名
*/
//注意大写字母表示可以被其他包访问
//改变包的名称
cool "goclass/pkg"  //将包名改成cool
/*
将一个包名完全引入 
*/
. "goclass/pkg"
//这样子我们可以访问一个包中的私有属性
基本数据类型

整数类型

我们一般直接使用uint 和int类型,如果你的电脑是64位,就会变成int64,如果是32,就会使int32.

uint只能是正数

浮点类型 :float64(一般使用这个) float32

后面跟的是精确度,就是小数点后面有几个数

只要类型不同,就会直接报错

怎么判断是什么类型?

var str string
str = "I'm a string"
fmt.Printf("%T",str)

数据类型的转化→使用一个包 strconv

package mainimport ("fmt""strconv"
)func main() {var str stringstr = "I'm a string"fmt.Printf("%T\n", str)num, _ := strconv.Atoi(str)fmt.Printf("转换str之后%T\n", num)num2 := 456str = strconv.Itoa(num2)fmt.Printf("%T\n", str)str = "3.14"f, _ := strconv.ParseFloat(str, 64)fmt.Printf("%T\n", f)f = 2.731str = strconv.FormatFloat(f, 'E', -1, 64)fmt.Printf("%T\n", str)str = "true"b, _ := strconv.ParseBool(str)fmt.Printf("%T\n",b)}

听视频,复习的感觉跟第一遍学的时候完全 不一样啊

复杂数据类型

不能以数字,特殊标记(¥)开头

流程控制语句
a:=0
//没有前增 ++a / --a
//只有后增,后减
a++
a--func main() {a := 1switch a {case 1:fmt.Println(a)fallthrough/*注意fallthrough并不会执行case2的判断语句*/case 2:fmt.Println("fallthrough之后的结果")default:fmt.Println("都不成立")}}/*
以前我一直觉得死循环没用,直到我刷了几个算法题
*/
/*
好的又复习到一个不记得的
continue是跳出本次循环
*/
a:=0
for a<10{a++if (a==5){continue}fmt.Println(a)//不会输出5
}//goto 
//还有这个,wqfunc main() {a := 1
A:  //之前可能阅读那个书籍的时候没有彻底阅读流程部分for a < 10 {a++if a == 5 {break Agoto B}fmt.Println(a)//不会输出5}
B:fmt.Println("我来到B了")}

数组:把同一类元素放在一起的集合

a := [3]int{1, 2, 3}
//[元素长度]元素类型{元素1,元素2...}fmt.Println(a)a := [3]int{1, 2, 3}fmt.Println(a)
//当我们不知道有多少个数的时候
b := [...]int{2423, 4, 3, 43, 4, 3, 4, 3, 43, 4}
//直到需要多杀个数,但是不知道具体值的时候var d = new([10]int)d[5] = 3fmt.Println(a, b, d)
//注意打印d的时候会含有&
//因为使用new创建的是一个指针

对同一类东西做同一个操作的时候,会很方便

len(数组) == cap(数组)

a := [3]int{1,2,3}
cl := a[:]
cl = a[1:]package mainimport "fmt"func main() {//数组的len和cap是一样的,但是切片不是a := [3]int{1, 2, 3}cl := a[:]fmt.Println("初始len and cap", len(cl), cap(cl))cl = append(cl, 5)fmt.Println(len(cl), cap(cl))cl = append(cl, 5)cl = append(cl, 5)cl = append(cl, 5)cl = append(cl, 5)fmt.Println(len(cl), cap(cl)) //cap到达一定的值会自动扩充到某个值//这里了解即可
}
//数组的len和cap是一样的,但是切片不是a := [3]int{1, 2, 3}cl := a[:]//讨论copy/*将后面的某一段复制到前面的一段,如果没有特定标记就是从0开始*/cl1 := a[1:]copy(cl, cl1)fmt.Println(cl) //expect 233a := [3]int{1, 2, 3}cl := a[:]//讨论copy/*如果说我们后面copy的数组len超过了前面的len,就会直接覆盖*/cl1 := append(cl, 5)cl1 = append(cl1, 5)copy(cl, cl1)fmt.Println(cl1)package mainimport "fmt"func main() {//数组的len和cap是一样的,但是切片不是a := [3]int{1, 2, 3}cl := a[:]//讨论copy/*如果我们想要指定覆盖*/cl1 := a[2:]copy(cl[1:2], cl1)fmt.Println(cl)
}//创造切片的方式
var aa []int//空数组aa := append(aa,5)aaa := make([]int,4) //有默认值

map

package mainimport "fmt"func main() {/*三种声明方式*/var m map[string]stringm = map[string]string{}m["name"] = "xzc"m["sex"] = "男"m2 := map[int]bool{}m2[1] = truem2[2] = falsem3 := make(map[string]string)m3["sex"] = "女"m4 := map[int]interface{}{} //规定入参结构和出参结构就行m4[1] = 1m4[2] = falsem4[3] = "xzc"fmt.Println(m4)//delete(变量名,key)delete(m4, 1)fmt.Println(m4)//当前长度fmt.Println(m["sex"])//通过for range 找到它的for k, v := range m4 {fmt.Println(k, v)}
}

func

func 函数名(入参1 入参类型,入参2 入参类型)(出参1 出参类型,出参2 出参类型)package mainpackage mainimport "fmt"/*func bb(data1 string) {fmt.Println(data1)}
*/
func main() {b := func(data1 string) {fmt.Println(data1)}/*大概就是b := bb*/b("Fuck")mo(1, "2", "23", "32")a := []string{"2", "3", "4", "5"}//将切片传入mo(2, a...)
}// 不知道入参有多少个,这样的我们成为不定项参数,一定要放在最后一个
func mo(data1 int, data2 ...string) {fmt.Println(data2)for k, v := range data2 {fmt.Println(k, v)}
}func A(data1, data2 int) (res1 string, res2 int) {//我们没有在函数内部定义res1 和 res2/*但是Go会自动帮助我们var ret1 stringvar res2 int*/return //省略   return res1,res2
}
func main() {//延迟调用函数defer last()//自知型函数//自动执行(func() {fmt.Println("我在这里执行,别人都管不着")})()mo()(4)
}// 闭包函数
func mo() func(int) {return func(num int) {fmt.Println("成功声明闭包函数", num)} //返回的要和回参一毛一样
}
func last() {fmt.Println("我要最后执行")
}

指针和地址

package mainimport "fmt"func main() {var a inta = 123fmt.Println(a)var b *int/*b = a指针不能指向数据只能指向具体值的地址*/b = &a // &内存地址fmt.Println(a, *b)*b = 456 //*内存地址fmt.Println(a, *b)}
package mainimport "fmt"func main() {//数组指针var a [5]stringa = [5]string{"1", "2", "3", "4", "5"}var aP *[5]stringaP = &afmt.Println(a, aP)//指针数组var arrP [5]*stringstr1 := "str1"str2 := "str2"str3 := "str3"str4 := "str4"str5 := "str5"arrP = [5]*string{&str1, &str2, &str3, &str4, &str5}for k, v := range arrP {fmt.Println(k, *v)}*arrP[3] = "333" //修改指针fmt.Println(str4)
}
package mainimport "fmt"func main() {var str1 = "我定义了"pointFunc(&str1)//指针传参fmt.Println(str1)
}func pointFunc(p1 *string) {*p1 = "我变了"
}

在map当中,我们通常不需要设置指针,map本身就是引用类型

struct

结构体是一个可以存储不同数据类型的数据类型

package mainimport "fmt"type Qm struct {Name    stringSex     stringHobbies []string
}func main() {/*三种声明方式var qm Qmqm.Name = "qm"qm.Sex = "男"qm.Hobbies = []string{"唱歌", "打游戏"}*//*qm := Qm{"xzc", "男", []string{"打游戏"},}*///建议用这种方法qm := Qm{Name:    "xzc",Sex:     "男",Hobbies: []string{"11223", "342"},}qmFunc(qm)/*qm := new(Qm)//声明了一个Qm的空结构体(类似于java实例)fmt.Println(qm)*/}func qmFunc(qm Qm)  {fmt.Println(qm)
}
    qm := Qm{Name:    "xzc",Sex:     "男",Hobbies: []string{"11223", "342"},}qmPtr := &qm.Name*qmPtr = "zcx" //会被看成*(qmPtr.Name),但实际上qmPtr是指向的qmfmt.Println(qm)qmPtr2 := &qm(*qmPtr2).Name = "zcx2"fmt.Println(qm)

结构体可以有自己的方法

package mainimport "fmt"type Qm struct {Name    stringSex     stringHobbies []stringHome    //复制进来,直接归属Qm
}type Home struct {P string
}func (h *Home) Open() {fmt.Println("open the", h.P)
}
func (q *Qm) Song(name string) (restr string) {fmt.Printf("%s唱了一首%v", q.Name, name)return "观众觉得很好听"
}
func main() {qm := Qm{Name:    "xzc",Sex:     "男",Hobbies: []string{"11223", "342"},}qmPtr := &qm.Name*qmPtr = "zcx" //会被看成*(qmPtr.Name),但实际上qmPtr是指向的qmfmt.Println(qm)qmPtr2 := &qm(*qmPtr2).Name = "zcx2"fmt.Println(qm)restr := qm.Song("惊雷")fmt.Print(restr)qm.P = "北京"fmt.Println(qm)qm.Open() //连他的方法都可以用
}

interface 接口

是一系列方法的集合,是一个规范

/*    var a Animalc := Cat{Name: "Tome",Sex:  "男",}a = ca.Eat()a.Run()*/var a Animala = Cat{Name: "Tome",Sex:  "男",}a.Eat()a.Run()
package mainimport "fmt"type Animal interface {Eat()Run()
}type Cat struct {Name stringSex  string
}type Dog struct {Name string
}// Cat is an animal
func (c Cat) Run() {fmt.Println(c.Name, "开始跑")
}func (c Cat) Eat() {fmt.Println(c.Name, "开始吃")
}
func (c Dog) Run() {fmt.Println(c.Name, "开始跑")
}func (c Dog) Eat() {fmt.Println(c.Name, "开始吃")
}
func main() {c := Dog{Name: "spake"}Myfunc(c)
}func Myfunc(a Animal) {//这就是泛型a.Eat()a.Run()
}
package mainimport "fmt"type Animal interface {Eat()Run()
}type Cat struct {Name stringSex  bool
}type Dog struct {Name string
}// Cat is an animal
func (c Cat) Run() {fmt.Println(c.Name, "开始跑")
}func (c Cat) Eat() {fmt.Println(c.Name, "开始吃")
}
func (c Dog) Run() {fmt.Println(c.Name, "开始跑")
}func (c Dog) Eat() {fmt.Println(c.Name, "开始吃")
}var L Animalfunc main() {c := Cat{Name: "Tom",Sex:  true,}Myfunc(c)L.Run()}
func Myfunc(a Animal) {L = a
}

goroutine and channel

Goroutine 是 Go 语言中的一种轻量级线程,它可以在相同的地址空间中并发执行多个函数。Goroutine 的创建和调度由 Go 运行时系统自动管理,不需要用户手动进行线程管理。

package mainimport ("fmt""sync"
)func main() {var wg sync.WaitGroupwg.Add(1) //协程管理器go Run(&wg)wg.Wait()
}func Run(wg *sync.WaitGroup) {fmt.Println("我跑起来了")wg.Done()
}
package mainimport "fmt"func main() {c1 := make(chan int)c1 <- 1fmt.Println(<-c1) //这里会被阻塞,因为c1没有缓冲区无法存放1,// 但是<-c1表示我需要从c1管道中找到一个值
}
package mainimport "fmt"func main() {c1 := make(chan int, 5)go func() {for i := 0; i < 10; i++ {c1 <- i //先会存5个,被取了之后,立马存}}()for i := 0; i < 10; i++ {fmt.Println(<-c1)} /*这里其实是等待c1通道发送消息过来*/
}
package mainimport "fmt"func main() {c1 := make(chan int, 5)/*var read <-chan int = c1var write chan<- int = c1close(c1)*/c1 <- 1c1 <- 2c1 <- 3c1 <- 4c1 <- 5close(c1)for v := range c1 {fmt.Println(v)//如果不关闭通道,接收方会一直读取}}
package mainimport "fmt"func main() {ch1 := make(chan int, 1)ch2 := make(chan int, 1)ch3 := make(chan int, 1)ch1 <- 1ch2 <- 2ch3 <- 3select { //随机执行case <-ch1:fmt.Println("ch1")case <-ch2:fmt.Println("ch2")case <-ch3:fmt.Println("ch3")default:fmt.Println("都不满足")}}
package mainimport "fmt"func main() {c := make(chan int)var read <-chan int = cvar write chan<- int = cgo SetChan(write)GetChan(read)
}
func SetChan(write chan<- int) {for i := 0; i < 10; i++ {fmt.Println("我是在write函数中")write <- i}
}
func GetChan(read <-chan int) {for i := 0; i < 10; i++ {fmt.Println("我从chan中取出", <-read)}
}
断言和反射

断言:把一个接口类型调用为原始结构并且可以使用原始结构的方法和属性

package mainimport "fmt"type User struct {Name stringAge  intSex  bool
}
type Student struct {UserClass string
}func (u User) SayName(name string) {fmt.Println("我的名字叫做", name)
}
func main() {u := User{"许智超",18,true,}check(u)//人为我们已经知道传入的是User
}
func check(v interface{}) {switch v.(type) {case User:fmt.Println(v.(User).Name)fmt.Println("我是User")case Student:v.(Student).SayName(v.(Student).Class)fmt.Println("我是Student")}//我们这些很麻烦//反射应运而生,不需要使用switch//可以直接知道它的类型
}
func check(inter interface{}) {t := reflect.TypeOf(inter)  //类型v := reflect.ValueOf(inter) //所有值for i := 0; i < t.NumField(); i++ {//NumField是指结构体中有几个值fmt.Println(v.Field(i))}fmt.Println(t, v)
}func check(inter interface{}) {v := reflect.ValueOf(inter) //所有值fmt.Println(v.FieldByName("Class"))
}
package mainimport ("fmt""reflect"
)type User struct {Name stringAge  intSex  bool
}
type Student struct {UserClass string
}func (u User) SayName(name string) {fmt.Println("我的名字叫做", name)
}
func main() {u := User{"许智超",18,true,}s := Student{u, "三年二班"}check(&s)fmt.Println(s)//人为我们已经知道传入的是User
}
func check(inter interface{}) {v := reflect.ValueOf(inter)e := v.Elem()//要使用下面的需要传入指针e.FieldByName("Class").SetString("四年二班")fmt.Println(inter)
}
package mainimport ("fmt""reflect"
)type User struct {Name stringAge  intSex  bool
}
type Student struct {UserClass string
}func (u User) SayName(name string) {fmt.Println("我的名字叫做", name)
}
func main() {u := User{"许智超",18,true,}check(u)
}
func check(inter interface{}) {v := reflect.ValueOf(inter)m := v.Method(0)m.Call([]reflect.Value{reflect.ValueOf("大牛逼")})
}

day 2从Mutex继续开始

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/802683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R-tree

R-tree 是一种空间访问方法的数据结构&#xff0c;用于有效地存储和检索多维空间数据&#xff0c;例如地理坐标、矩形或多边形。它特别适用于处理在空间数据库中常见的空间查询&#xff0c;例如最近邻查询、空间连接和空间范围查询。 R-tree 的设计目的是处理大量空间对象&…

在Windows系统上下载并安装MySQL的详细教程

在这篇教程中&#xff0c;介绍如何在Windows系统上下载并安装MySQL。以下是步骤&#xff1a; 1. 访问MySQL官方网站&#xff1a;https://www.mysql.com/ 2. 在主页上&#xff0c;向下滚动到“Developer Zone”&#xff0c;然后单击“MySQL Community (GPL) Downloads”。 3.…

c++——sort()函数

一、代码和效果 #include<bits/stdc.h> using namespace std;int main() {int a[6]{1,45,2,5,456,7};sort(a,a6);for(int i0; i<6; i){cout<<a[i]<<" "<<endl;}return 0; } 二、sort函数解析 &#xff08;从小到大&#xff09; std::so…

深入理解k8s kube-proxy

1、概述 我觉得只要大家知道kube-proxy是用来配置网络规则的而不是转发流量的&#xff0c;真正的流量由iptables/ipvs来转发就可以了。 网络是k8s的一个关键部分。理解k8s中网络组件如何工作可以帮助更好的设计和配置我们的应用。 kube-proxy就是K8s网络的核心组件。它把我们…

Vue3有哪些常用的API

Vue3提供了许多常用的API&#xff0c;这些API可以帮助开发者更高效地构建和管理Vue应用。以下是一些Vue3中常用的API及其功能描述&#xff1a; ref&#xff1a;ref函数用于创建一个响应式引用。它接受一个初始值&#xff0c;并返回一个响应式的对象&#xff0c;该对象的value属…

C# 系统学习(实例计算器)

下面是一个使用 C# 编写的简易计算器的示例代码。这个计算器将支持加、减、乘、除四种基本运算。 using System;class Calculator {static void Main(string[] args){Console.WriteLine("欢迎使用简易计算器&#xff01;");while (true){Console.WriteLine("请…

从“危”到“机”:HubSpot如何助企业转化出海营销CRM风险?

在全球化的大背景下&#xff0c;越来越多的企业选择出海拓展业务&#xff0c;以寻求更大的发展空间。然而&#xff0c;随着市场的扩大&#xff0c;企业在出海营销过程中也面临着各种风险。为了有效规避这些风险&#xff0c;许多企业选择借助HubSpot这样的专业营销软件。今天运营…

国际数字影像产业园构建成都文创产业园新地标!

国际数字影像产业园区&#xff0c;位于成都市金牛区的核心地带&#xff0c;不仅地理位置得天独厚&#xff0c;而且周边配套设施完善&#xff0c;交通便捷&#xff0c;不止成为北二环的新地标&#xff0c;正在构建成都文创产业园新地标&#xff01; 国际数字影像产业园这一片区…

专利年费缴纳后电子票据

专利年费缴纳后的电子票据 随着信息技术的快速发展&#xff0c;电子票据作为一种新型的支付与记录方式&#xff0c;已经深入到了我们日常生活的各个方面。特别是在知识产权领域&#xff0c;专利年费的缴纳也开始逐步实现电子化。 一、专利年费缴纳的重要性 专利年费是专利权…

Windows本地Clion运行CUDA程序

先要条件 在本地安装Visual Studio并且安装好CUDA。建议先安装VS而不是CUDA。如果先安装CUDA&#xff0c;安装遇到问题可参考&#xff1a;https://blog.csdn.net/Cony_14/article/details/137510909 关键步骤 CLion中创建CUDA项目 左上角-新建-项目-CUDA可执行文件。 针对…

5【PS让图片动起来】系列3-【时间轴 花瓣飘落】

【问题介绍】上章将花瓣拆分为一片片花瓣&#xff0c;现在让这片花瓣【动态】飘落吧~ PS选择“窗口”→ “时间轴” 下方弹出时间轴&#xff0c;其中01:00f就是这个位置为1秒的。中间的0 10f 20f等&#xff0c;为帧速率&#xff0c;也就是一秒的动画时间里有几帧的意思 下图…

Linux进阶篇:磁盘管理(二):LVM的创建、格式化和使用

Linux磁盘管理&#xff08;二&#xff09;&#xff1a;LVM的创建、格式化和使用 一、LVM原理回顾 LVM的工作原理进行一个总结&#xff1a; (1)物理磁盘被格式化为PV&#xff0c;空间被划分为一个个的PE (2)不同的PV加入到同一个VG中&#xff0c;不同PV的PE全部进入到了VG的PE…

2024年【R1快开门式压力容器操作】最新解析及R1快开门式压力容器操作试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【R1快开门式压力容器操作】最新解析及R1快开门式压力容器操作试题及解析&#xff0c;包含R1快开门式压力容器操作最新解析答案和解析及R1快开门式压力容器操作试题及解析练习。安全生产模拟考试一点通结合国家…

比特币革命:刚刚开始

作者&#xff1a;Marius Farashi Tasooji 编译&#xff1a;秦晋 要充分理解比特币及其含义&#xff0c;首先必须理解什么是价值&#xff0c;什么是货币。以及是什么赋予资产价值&#xff1f; 这个问题看似愚蠢&#xff0c;但实际上非常有趣。我们的生活是由我们消费或出售的物品…

scrapy 爬取m3u8视频

scrapy 爬取m3u8视频 【一】效果展示 爬取ts文件样式 合成的MP4文件 【二】分析m3u8文件路径 视频地址&#xff1a;[在线播放我独自升级 第03集 - 高清资源](https://www.physkan.com/ph/175552-8-3.html) 【1】找到m3u8文件 这里任务目标很明确 就是找m3u8文件 打开浏览器…

达梦数据库非空约束错误解决,明明插入空字符串,但还是触发非空约束

1、今天在做增删改查的时候&#xff0c;发现一个问题&#xff0c;就是我的某字段设置为NOT NULL非空约束&#xff0c;但在插入空字符串的时候还是触发非空约束报错&#xff0c;这令我十分费解&#xff0c;我又没有传null&#xff0c;为什么还会触发非空约束呢&#xff1f;苦思良…

CPU和GPU分别是什么?主要区别是什么?

CPU与GPU的区别 定义性能特点应用领域结构与体积控制与协同工作特殊用途与限制脑图 定义 CPU: 中央处理器&#xff0c;负责解释并执行指令GPU: 图形处理器&#xff0c;专用于图形和视频处理 性能特点 CPU 计算量小&#xff0c;适合复杂运算结构组成复杂&#xff0c;控制逻辑…

老王讲IT:高级变量类型

IT老王&#xff1a;高级变量类型 目标 列表 元组 字典 字符串 公共方法 变量高级 知识点回顾 Python 中数据类型可以分为 数字型 和 非数字型 数字型 整型 (int) 浮点型&#xff08;float&#xff09; 布尔型&#xff08;bool&#xff09; 真 True 非 0 数 —— 非零…

一文了解ERC404协议

一、ERC404基础讲解 1、什么是ERC404协议 ERC404协议是一种实验性的、混合的ERC20/ERC721实现的&#xff0c;具有原生流动性和碎片化的协议。即该协议可让NFT像代币一样进行拆分交易。是一个图币的互换协议。具有原生流动性和碎片化的协议。 这意味着通过 ERC404 协议&#xf…

python--正则表达式-分组,贪婪模式,懒惰模式

分组&#xff1a; 分组在正则表达式中充当二次筛选 re.match(r"<[a-zA-Z].*>(.*)</[a-zA-Z]>", "<a>这个是百度的链接</a>") <re.Match object; span(0, 15), match<a>这个是百度的链接</a>> 贪婪与懒惰模式&am…