Go语言基础与实践学习 - Javaer快速入门Go | 豆包MarsCode AI 刷题

69 阅读6分钟

Go与Java的本质区别 - 思考

  • 语法:Go和Java都是C 家族语言,所以它们的语法相似,由此Javaer转Go也不会太困难;甚至在学习过程中,Go语言的“大部分情况语句结尾不需要分号”更合我胃口,不过创建变量时Go需要“变量 类型”的顺序,这会让学C入门的我写起来比较别扭

  • 垃圾回收:因为基于C,两个语言都需要垃圾回收机制,相比之下Go作为新兴者在这一点似乎做的更好

  • 跨平台:Java依赖JVM,而Go将代码编译为目标平台的二进制文件,相比于Go将代码编译成目标平台的二进制文件,Java的JVM可以更好更稳定地解决跨平台问题

  • 类与结构体:Java面向对象,有类和对象的概念,而Go用结构体表示复杂数据;我觉得这是两个主后端语言本质的不同,Go 是一种命令式语言,Java 是一种声明式语言。两种语言的差异让程序员关注的方向不同:Java 要求开发人员更多地地关注程序的业务逻辑,知道如何创建、过滤、修改和存储数据。系统底层和数据库方面的东西都是通过配置和注解来完成的(比如通过 Spring Boot 等通用框架)。我们尽可能把枯燥乏味的东西留给框架去做。这样做很方便,但控制也反转了,限制了我们优化整个过程的能力。

// reference:程序员技术选型:写Go还是Java? - 知乎

字节内部课/青训营X豆包MarsCode 技术训练营 学习笔记

  • 目前已经学习Go语言入门指南课程的Go语言基础、四个实战案例、协程、依赖管理、测试、项目模块,有Java基础入门起来会很快,"=="包围的章节为重点内容

二、==基础语法==

基本格式、编译运行的命令:

image-20241104135619353

变量:

image-20241104135845566

if else:后面没有括号

  • 括号也可以有,编译的时候会去掉

image-20241104135949712

循环:只有for循环

image-20241104140115256

switch case:

image-20241104140343495

数组:

image-20241104140502164

切片:

image-20241104140733464

map:

image-20241104141158708

range:

image-20241104141505990

函数:

image-20241104141648717

指针:修改变量的值

  • 不以指针传入的变量只是拷贝,需要修改值时要传入指针

image-20241104141812412

结构体:

  • 同样有结构体指针,可对属性进行修改,且有时能避免一些大结构体拷贝的开销

image-20241104141953169

结构体方法:

image-20241104142302907

错误处理:error类型,返回值传递,if处理

  • 不同于java的异常,go用返回值代表错误,用if else处理错误

image-20241104142533132

字符串操作:“strings”包

  • 注意一个中文会对应多个字符

image-20241104142625182

打印:“fmt”包,格式字符

image-20241104142747597

json操作:“encoding/json”包

image-20241104143222520

时间处理:“time”包

image-20241104160110598

数字解析:“strconv”包

image-20241104160316369

进程信息:“os”、“os/exec”包

image-20241104160751232

三、实战

1)猜谜游戏:

  • 一、==生成随机数==:注意需要设置随机数种子(时间),不然每次运行都是相同的数字

image-20241104162442939

  • 二、==用户输入==:用”bufio”包下方法来读取用户输入
  • Ps:后面可以通过scanf更快的读取

image-20241104162812278

  • 三、判断:

image-20241104162932139

  • 四、完整实现:

image-20241104163031193

2)==在线词典==:

* 需求:
  • 运行该方法时,传入单词,方法打印该单词的音标、含义等
  • 考点:需要发送http请求,解析json字符串、代码生成等

image-20241104163209575

* 实现:
  • 一、抓包:在网页中看请求

image-20241104163542257

  • 二、复制请求的curl命令:

image-20241104164107774

  • 三、打开==代码生成网址==:转换为go语言的请求
  • 由于header比较复杂,少部分代码可能发生编译错误,直接删掉

image-20241104164149322

  • Ps:看看生成的代码(输入为good的情况)

image-20241104165053984

  • 四、改为变量输入(输入不固定):上面代码生成能看出==request body==的结构,直接创建对应的结构体对象,通过json序列化并转换为byte数组来当作newRequest的参数

image-20241104184745818

  • 五、==解析response body==,更好的打印出人能看的结果:
  • 和request body一样,最好是写一个对应的结构体,然后后面打印这个返回结果(response body)的一些属性
  • 方法:打开代码生成网站,将抓包的response body的json字符串传进去,就能生成对应的go的结构体

image-20241104185301669

image-20241104185328603

  • 用生成的结构体获取到返回的response body数据,反序列化并直接打印:

image-20241104185449137

  • 六、将打印内容改为需求中需要打印的信息

image-20241104185722998

  • 七、获取该进程(main方法)的变量,取第二个作为参数word,传入打印方法

image-20241104190020328

3)实现SOCKS5代理:

* 小demo:
  • 需求:创建一个基于tcp连接的服务(本机的xxx端口),读取用户端发送的报文(如字符串),返回相同的字符串
  • ==重点==:怎么实现tcp端口,开放并获取请求的字符串,并处理和打印出来

image-20241104192005116

四、==语言进阶 - 协程==

1)协程:Goroutine

  • 并发:一个核,多线程抢夺时间片
  • 并行:多个核,多线程一起运行 -> Go能充分发挥多核优势
  • 线程:属于内核态,系统级别,它的创建等操作会重很多
  • ==协程==(Goroutine):属于用户态,它由go创建和调度,操作轻(轻松应对上万协程)
  • 方法:通过在函数前加上go关键字来为函数创建协程

image-20241104193434764

2)协程间通信:channel

  • CSP:通信与共享内存
  • Go提倡通过通道来共享内存

image-20241104194126042

  • 无缓冲通道:直接传
  • 有缓冲通道:规定队列中的元素数量,满了会有阻塞

image-20241104195110174

  • 通过通道共享内存的具体实现:

image-20241104194947105

  • 补充(不推荐):通过加锁实现并发的安全

image-20241104195344171

3)WaitGroup:协程计算器

  • 前面介绍协程用到的sleep不够优雅(可能出错),可以用WaitGroup更加精确的停止

image-20241104195542143

  • 代码:

image-20241104195649659

五、==依赖管理==

1)Go Module介绍:

image-20241104200254147

2)go.mod组成:

image-20241104200608072

  • ①go.mod的版本规则:

image-20241104200730641

  • ②直接依赖、间接依赖:

image-20241104200853856

  • ③incompatible:没有go.mod文件且主版本2+的依赖会有该后缀(表示可能有些代码不兼容)

image-20241104201146842

3)依赖关系冲突:选择最低的兼容版本

image-20241104201329357

4)依赖分发:Proxy

  • 通过代理仓库来获取依赖:==修改GOPROXY变量实现==

image-20241104201553350

5)go get工具、go mod工具:

image-20241104201704559

image-20241104201815297

六、==测试==

1)单元测试:

  • 一、组成:

image-20241105095429902

  • 二、规则:
  • Ps:如果测试方法不以大写Test开头,ide就不会出现运行的按钮提示

image-20241105095729396

  • 例:

image-20241105095833639

  • 结果:

image-20241105095937696

  • 三、使用第三方assert包进行校验

image-20241105100018442

  • 四、覆盖率

image-20241105100417776

  • 提高覆盖率:

image-20241105100544426

  • tips:代码设计时,函数应单一职责,这使得测试的单元粒度小,而覆盖率会更高

image-20241105100635887

2)Mock

  • 一、单元测试的要求
  • 幂等:每次运行的结果应该一样
  • 稳定:单元测试应该是相互隔离的,我们在任何时候都能运行
  • 而一些复杂的依赖,比如数据库、cache等,由于网络等因素会造成一些问题 -> Mock机制

image-20241105101055037

  • 例:一些问题
  • 函数依赖于一些本地的文件,一旦文件被修改,就不能正常地测试了

image-20241105101334765

  • 一、介绍mock包:monkey
  • 打桩:

image-20241105101657073

  • 例:用Patch()打桩函数ReadFirstLine(),修改逻辑为直接返回值“line110”

image-20241105101855524

3)基准测试:

  • 概念:指测试代码的运行性能、cpu损耗等
  • 例:

image-20241105102313611

image-20241105102605558

  • 扩展:解决rand包性能差问题,介绍一个开源fastrand(适用大部分场景)

image-20241105102728977