tip: 无论是变量、方法还是struct的访问权限控制都是通过命名控制的,命名的首字母是大写就相当于java中的public,小写的话就是private,(private只有本包可以访问)

1 go的变量声明

普通变量

特点: 变量类型后置

方式1var num int = 1
方式2:
num := 1					// := 会帮我们自动匹配数据类型(最常用)
方式3var num = 1

常量

还是通过const关键字声明(和c是一样的)const (//声明常数列表ZHANGSAN = 1LISI = 2....
)并且我们可以使用iota关键字进行简写
const (ZHANGSAN = iota + 1      //iota默认是0,每次被使用后都会+1LiSI					//等同于LISI = iota + 1, 但是公式没有发生变化所以可以省略
)常量使用:
fmt.println("ZHANGSNA = ", ZHANGSAN)

2 go的函数/方法声明

特点: func (绑定struct名 类型) 函数名(形参名 形参类型, …) 返回类型 {函数体}

func print(s string) string {....
}go当中的方法是可以有多个返回值的:
func play() (string, string) {return zhangsan, lisi
}//多返回值接收
name1, name2 := play()

3.对象

声明

特点: go语言的对象是一种组合概念,由结构体+一系列方法构成

type关键字:定义自定义类型type person struct {name stringage int
}func (p *person) setName(name string) {p.name = name
}上述代码就等同于java中的如下代码:
private class person {private String name;private int age;private void setName(String name) {this.name = name;}
}"(p *person)"代表这个方法绑定person这个struct为什么要使用"*person"?
因为go中的对象(struct)是值类型(也就是java中的基本类型),因此不传入指针的话修改也不生效(需要一点c的指针基础)

类继承

type human struct {name stringage int
}type man struct {human // 就代表man继承了human对象sex int
}//man的创建
man1 := man{human{"zhangsan", 18}, 1}

4 init方法

特点: 导包时执行的初始化方法

package p1import "fmt"func init() {fmt.println("p1, init")
}如果我们引入这个包,那么就会执行p1的init方法

5 指针

go中的指针和c是一样的

6 defer关键字

特点: 在defer所在的代码块执行完后执行,类似java的finally或c++的析构函数

使用场景: 文件关闭、连接关闭、资源释放等

func print() {defer fmt.println("2..")fmt.println("1..")
}
输出:先12//defer可以有多个,通过栈结构存储
func print() {defer fmt.println("2..")		//2进栈defer fmt.println("3..")		//3进栈fmt.println("1..")
}
输出:先132tip:deferreturn的执行顺序,因为defer是在所在方法的生命周期结束后才会执行
func deferCall() {fmt.println("defer...")
}
func returnCall() {fmt.println("return...")
}
func deferAndReturn() {defer deferCall()return returnCall()
}
func main() {deferAndReturn()
}
输出: return...defer...

7 数组与动态数组

声明

固定数组(常用)
arr := [3]int{1,2,3} 动态数组(也叫切片slice)
arr := []int{1, 2, 3} 或   //虽然我们只添加了三个初始值,但是我们还可以往后继续添加
arr1 := make([]int, 3)    //开辟大小为3的数组,但是没有设置初始值
arr2 := make([]int, 3, 5) //开辟一个大小为3,容量为5的切片(arr[3]和arr[4]实际还不可以访问)
容量的概念就是我们声明了这个空间但是我没创建(也就是我告诉你这有但是现在还没有),大小就是现在实际有的切片扩容:当容量不够时,会自动扩容为当前容量的2倍,没指定容量的话就是切片大小对动态数组的操作与python中的切片操作类似。tip: 
go当中的固定数组是一种直接类型,不像是java中的引用类型,所以[3]int 和 [4]int不是同一类型的,所以在使用固定数组作为方法形参的时候如果想要改变内容应该传入指针。
而动态数组是引用类型,type(arr)得到的是[]int.

遍历

arr := []int{1,2,3,4}方式1for index, value := range arr {fmt.println("下标是:", index)fmt.println("内容是:", value)
}方式2for i := 1, i < len(arr), i++ {fmt.println(arr[i])
}

8 map

声明

var myMap map[String]string				//[]内是key类型,外是value类型//开辟空间
myMap := make(map[string]string, 10)//有初始值创建
myMap := map[string]string{"one":	"zhangsan""two":	"lisi"
}

使用

myMap := make(map[string]string)
//增
myMap["one"] = "zhangsan"
myMap["two"] = "lisi"//删
delete(myMap, "one")//改
myMap["two"] = "wangwu"//查
value := myMap["two"]// 遍历
for key, value := range myMap {}

9 多态

特点: 实现接口

type animal interface {show()play()
}
// cat实现了animal接口, 是通过实现接口方法
type cat struct {name string
}
func (c *cat) show() {fmt.println("这是一只猫")
}
func (c *cat) play() {fmt.println("猫在玩耍")
}

10.interface{}

特点: 通用数据类型,几乎所有类型都实现了interface{}

func call(this interface{}) {fmt.println("this is ", this)// 类型断言value, res := this.(string) // 判断this是不是是tring类型,会返回两个数据一个是this本身一个是判断结果(bool)
}type human struct {name string
}func main() {human1 := human{"zhangsan"}//call 方法可以接收任何类型call(human1)call(1)call("lisi")
}

11 pair

任何变量都会有一个piar对变量描述,这个piar结构如下:<type, value>,type代表变量的类型,value代表变量存储的值。

type又分为static type(基本类型,如:int、char这些)和concrete type(引用类型,如:切片)

12 反射

go提供了reflect包实现反射功能,其中有两个核心方法TypeOf()和ValueOf(), 分别用来获取参数对象的类型与值。

反射基本使用

package mainimport ("fmt""reflect"
)type User struct {Name stringAge int
}func (this User) Call() {   //这里写*User会识别不到方法,原因在后面fmt.Println("User is call...")fmt.Printf("%v\n", this)
}func main() {user :=  User{"zhangsan", 18}DoFiledAndMethod(user)
}func DoFiledAndMethod(input interface{}) {// 获取input信息t := reflect.TypeOf(input)fmt.Println("type:", t.Name())v := reflect.ValueOf(input)fmt.Println("value:", v)// 遍历结构体的所有字段for i := 0; i < t.NumField(); i++ {field := t.Field(i)value := v.Field(i).Interface()fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)}methodNum := t.NumMethod()fmt.Printf("the User has %d methods\n", methodNum)// 通过type调用方法for i := 0; i < t.NumMethod(); i++ {method := t.Method(i)fmt.Printf("%s: %v\n", method.Name, method.Type)}
}

Go 的方法集规则

Go 的方法集规则如下:

  1. 值类型(T 的方法集包含所有接收者为 T 的方法。
  2. 指针类型(*T 的方法集包含所有接收者为 T*T 的方法。

因此:

  • User 值类型的方法集:只有接收者为 User 的方法。
  • *User 指针类型的方法集:接收者为 User*User 的方法。

13 标签

在 Go 语言中,标签(Tags) 是结构体字段的元数据,通常用于编码/解码(如 JSON、XML)、ORM 映射(如 GORM)、验证(如 validator)等场景。标签以反引号 `` 包裹,格式为 key:“value”,多个标签用空格分隔。

package mainimport ("fmt""encoding/json"
)type User struct {Name string		`json:"name"`Age int			`json:"age"`
}func main() {user := User{"zhangsan", 18}// 结构体 -> jsonjsonData, _ := json.Marshal(user)fmt.Println(string(jsonData))//json -> 结构体myUser := User{}err := json.Unmarshal(jsonData, &myUser)if(err != nil) {fmt.Println("err: ", err)return}fmt.Printf("%v\n", myUser)
}输出:
{"name":"zhangsan","age":18}
{zhangsan 18}

14 协程

协程(Goroutine) 是一种轻量级的并发执行单元,由 Go 运行时(runtime)管理,用于实现高并发编程。

go语言对于协程的设计是将原先线程中用户态部分分离出来了,这样不需要频繁的切换,而原线程中的内核态部分成为新的线程复杂管理协程。

协程结构:

在这里插入图片描述

GMP模型控制:

关键组件

  1. G (Goroutine)
    • 包含执行栈、程序计数器(PC)、状态(运行/阻塞)。
    • 通过 go 关键字创建,轻量且可动态扩缩。
  2. P (Processor)
    • 协程调度器,绑定到 M 上运行。
    • 维护一个本地 Goroutine 队列(优先调度本地队列)。
  3. M (Machine)
    • 操作系统线程,真正执行计算的单元。
    • 由 P 分配任务,空闲时会被回收或休眠。

调度流程:

1. G 创建 → 放入 P 的本地队列(或全局队列)。//只用本地队列满会放入全局队列
2. M 获取 G → 从绑定的 P 的队列中取 G 执行。
3. G 阻塞(如 I/O)→ 该阻塞协程从本地队列移除,M解绑P,由M负责该阻塞协程,解绑后的P绑定一个新的线程,P可以正常工作去调度其他G。
4. G 就绪 → 被放回队列,等待 M 执行。

在这里插入图片描述

Goroutine 解决了线程的哪些痛点?

(1) 高创建和切换成本
  • 线程问题:每个线程需要分配较大的栈(1MB+),创建和切换涉及内核态操作,开销大。
  • Goroutine 方案:初始栈仅 2KB,由 Go 运行时在用户态调度,切换成本极低。
(2) 并发数量受限
  • 线程问题:受限于内存和内核调度,通常只能创建几千个线程。
  • Goroutine 方案:轻量级设计,单机可轻松支持百万级并发,还有协程调度器的存在支持多对多的调度关系。
(3) 共享内存导致的竞态问题
  • 线程问题:多线程需通过锁(mutex)同步,易引发死锁、数据竞争。
  • Goroutine 方案:通过 Channel 通信,避免显式锁,更安全。
(4) 阻塞导致线程浪费
  • 线程问题:一个线程阻塞(如 I/O 操作)时,线程池中的线程被占用,影响整体吞吐量。
  • Goroutine 方案:阻塞时,Go 运行时会自动挂起该 Goroutine,复用线程执行其他任务。

协程的使用

package mainimport ("fmt""time"
)
func print() {i := 0for {i++fmt.Printf("new Goroutine: i = %d\n", i)time.Sleep(1 * time.Second)}
}func main() {go print() // 创建协程执行print方法i := 0for {i++fmt.Printf("main Goroutine: i = %d\n", i)time.Sleep(1 * time.Second)}
}// 也可以通过匿名调用的方式
func main() {go func ()  {i := 0for {i++fmt.Printf("new Goroutine: i = %d\n", i)time.Sleep(1 * time.Second)}}() // 括号中填入方法的参数,我这是无参就没填i := 0for {i++fmt.Printf("main Goroutine: i = %d\n", i)time.Sleep(1 * time.Second)}
}//执行结果
main Goroutine: i = 1
new Goroutine: i = 1
new Goroutine: i = 2
main Goroutine: i = 2
main Goroutine: i = 3
new Goroutine: i = 3
new Goroutine: i = 4
main Goroutine: i = 4

15 channel

用于协程间通信的一种方式,分为无缓冲channel有缓冲channel

无缓冲channel:channel中同一时间只能存在一个数据

package mainimport ("fmt""time"
)// 1
func main() { // 主协程c := make(chan int)fmt.Println("main Goroutine try to read from channel")num := <-cfmt.Println(num)go func (){  //子协程c <- 1fmt.Println("already write")}()
}// 2
func main() {c := make(chan int)go func (){c <- 1fmt.Println("already write")}()fmt.Println("main Goroutine not read from channel")i := 0for {i++fmt.Println(i)time.Sleep(1 * time.Second)}
}输出:
// 1
fmt.Println("main Goroutine try to read from channel")
1// 2
main Goroutine not read from channel
1
2
3
4
5

子协程向channel中写入数据后会在此阻塞直到数据被取走,同样如果主协程想要从channel中读取数据但目前channel中没有数据主协程也会阻塞等待。

有缓冲channel:其与阻塞队列的功能非常相似,允许存在多个数据在channel中,如果从空channel中获取元素或向满channel中发送元素则会触发阻塞。

// 声明有缓冲channel
ch := make(chan int 3) //创建缓冲大小为3的有缓冲channel

虽然channel和阻塞队列功能类似但他俩在实现上还是有很大的不同,感兴趣的可以去了解一下。

关闭channel:

channel一旦关闭就无法向channel中发送数据,但如果缓冲区内还有数据则还可以读取。

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

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

相关文章

量化面试绿皮书:19. 相关系数

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 19. 相关系数 假设有三个随机变量x、y和z。 x与y之间的相关系数为0.8&#xff0c;x与z之间的相关系数也是0.8。 Q: 那么y与z之间的最大相关…

新生活的开启:从 Trae AI 离开后的三个月

很久没有写文章了&#xff0c;想借着入职新公司一个月的机会&#xff0c;和大家唠唠嗑。 离职 今年2月份我从字节离职了&#xff0c;结束了四年的经历&#xff0c;当时离开的核心原因是觉得加班时间太长了&#xff0c;平均每天都要工作15&#xff0c;16个小时&#xff0c;周末…

LLM部署之vllm vs deepspeed

部署大语言模型(如 Qwen/LLaMA 等)时,vLLM 与 DeepSpeed 是当前主流的两种高性能推理引擎。它们各自专注于不同方向,部署流程也有明显区别。 vLLM 提供极致吞吐、低延迟的推理服务,适用于在线部署;DeepSpeed 更侧重训练与推理混合优化,支持模型并行,适用于推理 + 微调/…

Git(二):基本操作

文章目录 Git(二)&#xff1a;基本操作添加文件修改文件版本回退撤销修改情况一&#xff1a;工作区的代码还没有 add情况⼆&#xff1a;已经 add 但没有 commit情况三&#xff1a;已经 add 并且也 commit 删除文件 Git(二)&#xff1a;基本操作 添加文件 首先我们先来学习一个…

nginx + ffmpeg 实现 rtsp视频实时播放和历史播放

nginx和ffmpeg 的安装请参考我的另一篇文章 Nginxrtmpffmpeg搭建视频转码服务_nginx-rtmp-module-master-CSDN博客 目录 1、整体方案设计如图 2、nginx下目录创建和配置文件创建 3、创建视频流生成脚本 4、修改nginx配置 5、管理界面 (video.html) 6、ffmpeg后台启动 …

全国产!瑞芯微 RK3576 ARM 八核 2.2GHz 工业核心板—硬件说明书

前 言 本文为创龙科技 SOM-TL3576 工业核心板硬件说明书,主要提供 SOM-TL3576 工业 核心板的产品功能特点、技术参数、引脚定义等内容,以及为用户提供相关电路设计指导。 为便于阅读,下表对文档出现的部分术语进行解释;对于广泛认同释义的术语,在此不做注释。 硬件参考…

web3 浏览器注入 (如 MetaMask)

以下是关于 浏览器注入方式(如 MetaMask) 的完整详解,包括原理、使用方法、安全注意事项及常见问题解决方案: 1. 核心原理 当用户安装 MetaMask 等以太坊钱包扩展时,钱包会向浏览器的 window 对象注入一个全局变量 window.ethereum,这个对象遵循 EIP-1193 标准,提供与区…

解密提示词工程师:AI 时代的新兴职业

大家好!在人工智能飞速发展的当下&#xff0c;有一个新兴职业正悄然崛起——提示词工程师。他们虽不如数据科学家般广为人知&#xff0c;却在 AI 应用领域发挥着独特且关键的作用。 何为提示词工程师&#xff1f; 提示词工程师专注于设计和优化与 AI 模型进行交互的提示词&…

linux 下 jenkins 构建 uniapp node-sass 报错

背景: jenkins 中构建 uniapp 应用 配置: 1. 将windows HbuilderX 插件目录下的 uniapp-cli 文件夹复制到 服务器 /var/jenkins_home/uniapp-cli 2. jenkins 构建步骤增加 执行 shell ,内容如下 echo ">> 构建中..."# 打包前端 export LANGen_US.UTF-8…

QT常见问题(1)

QT常见问题&#xff08;1&#xff09; 1.问题描述 Qt在编译器中直接运行没有任何问题&#xff0c;但是进入exe生成目录直接双击运行就报错&#xff1a;文件无法定位程序输入点_zn10qarraydata10deallocateepsyy于动态链接库。 2.问题原因 这个错误通常是由于程序运行时找不…

『大模型笔记』第2篇:并发请求中的 Prefill 与 Decode:优化大语言模型性能

『大模型笔记』并发请求中的 Prefill 与 Decode:优化大语言模型性能 文章目录 一. Token 生成的两个阶段:Prefill 和 Decode1.1. 指标分析1.2. 资源利用率分析二. 并发处理机制2.1. 静态批处理 vs 持续批处理(Static Batching vs. Continuous Batching)2.2. Prefill 优先策略…

JVM(7)——详解标记-整理算法

核心思想 标记-整理算法同样分为两个主要阶段&#xff0c;但第二个阶段有所不同&#xff1a; 标记阶段&#xff1a; 与标记-清除算法完全一致。遍历所有可达对象&#xff08;从 GC Roots 开始&#xff09;&#xff0c;标记它们为“存活”。 整理阶段&#xff1a; 不再简单地清…

进程虚拟地址空间

1. 程序地址空间回顾 我们在学习语言层面时&#xff0c;会了解到这样的空间布局图&#xff0c;我们先对他进行分区了解&#xff1a; 如果以静态static修饰的变量就会当成已初始化全局变量来看待&#xff0c;存放在已初始化数据区和未初始化数据区之前。 如果不用static修饰test…

C语言学习day17-----位运算

目录 1.位运算 1.1基础知识 1.1.1定义 1.1.2用途 1.1.3软件控制硬件 1.2运算符 1.2.1与 & 1.2.2或 | 1.2.3非 ~ 1.2.4异或 ^ 1.2.5左移 << 1.2.6右移 >> 1.2.7代码实现 1.2.8置0 1.2.9置1 1.2.10不借助第三方变量&#xff0c;实现两个数的交换…

【linux】简单的shell脚本练习

简单易学 解释性语言&#xff0c;不需要编译即可执行 对于一个合格的系统管理员来说&#xff0c;学习和掌握Shell编程是非常重要的&#xff0c;通过shell程序&#xff0c;可以在很大程度上简化日常的维护工作&#xff0c;使得管理员从简单的重复劳动中解脱出来 用户输入任意两…

机构运动分析系统开发(Python实现)

机构运动分析系统开发(Python实现) 一、引言 机构运动分析是机械工程的核心内容,涉及位置、速度和加速度分析。本系统基于Python开发,实现了平面连杆机构的完整运动学分析,包含数学建模、数值计算和可视化功能。 二、系统架构设计 #mermaid-svg-bT8TPKQ98UU9ERet {font…

工程师生活:清除电热水壶(锅)水垢方法

清除电热水壶&#xff08;锅&#xff09;水垢方法 水垢是水加热时自然形成的钙质沉淀物&#xff0c;常粘附在水壶内壁及发热盘上。它不仅影响水的品质&#xff0c;还会缩短水壶的使用寿命&#xff0c;因此需要定期清除。建议根据各地水质不同&#xff0c;每年除垢 2 至 4 次。…

[分布式并行策略] 数据并行 DP/DDP/FSDP/ZeRO

上篇文章【[论文品鉴] DeepSeek V3 最新论文 之 DeepEP】 介绍了分布式并行策略中的EP&#xff0c;简单的提到了其他几种并行策略&#xff0c;但碍于精力和篇幅限制决定将内容分几期&#xff0c;本期首先介绍DP&#xff0c;但并不是因为DP简单&#xff0c;相反DP的水也很深&…

LeeCode144二叉树的前序遍历

项目场景&#xff1a; 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 解释&#xff1a; 示例 2&#xff1a; 输入&#xff1a;root [1,2,3,4,5,null,8,null,null,6,7…

日本生活:日语语言学校-日语作文-沟通无国界(3)-题目:わたしの友達

日本生活&#xff1a;日语语言学校-日语作文-沟通无国界&#xff08;&#xff13;&#xff09;-题目&#xff1a;わたしの友達 1-前言2-作文原稿3-作文日语和译本&#xff08;1&#xff09;日文原文&#xff08;2&#xff09;对应中文&#xff08;3&#xff09;对应英文 4-老师…