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基础入门起来会很快,"=="包围的章节为重点内容
二、==基础语法==
基本格式、编译运行的命令:
变量:
if else:后面没有括号
- 括号也可以有,编译的时候会去掉
循环:只有for循环
switch case:
数组:
切片:
map:
range:
函数:
指针:修改变量的值
- 不以指针传入的变量只是拷贝,需要修改值时要传入指针
结构体:
- 同样有结构体指针,可对属性进行修改,且有时能避免一些大结构体拷贝的开销
结构体方法:
错误处理:error类型,返回值传递,if处理
- 不同于java的异常,go用返回值代表错误,用if else处理错误
字符串操作:“strings”包
- 注意一个中文会对应多个字符
打印:“fmt”包,格式字符
json操作:“encoding/json”包
时间处理:“time”包
数字解析:“strconv”包
进程信息:“os”、“os/exec”包
三、实战
1)猜谜游戏:
- 一、==生成随机数==:注意需要设置随机数种子(时间),不然每次运行都是相同的数字
- 二、==用户输入==:用”bufio”包下方法来读取用户输入
- Ps:后面可以通过scanf更快的读取
- 三、判断:
- 四、完整实现:
2)==在线词典==:
* 需求:
- 运行该方法时,传入单词,方法打印该单词的音标、含义等
- 考点:需要发送http请求,解析json字符串、代码生成等
* 实现:
- 一、抓包:在网页中看请求
- 二、复制请求的curl命令:
- 三、打开==代码生成网址==:转换为go语言的请求
- 由于header比较复杂,少部分代码可能发生编译错误,直接删掉
- Ps:看看生成的代码(输入为good的情况)
- 四、改为变量输入(输入不固定):上面代码生成能看出==request body==的结构,直接创建对应的结构体对象,通过json序列化并转换为byte数组来当作newRequest的参数
- 五、==解析response body==,更好的打印出人能看的结果:
- 和request body一样,最好是写一个对应的结构体,然后后面打印这个返回结果(response body)的一些属性
- 方法:打开代码生成网站,将抓包的response body的json字符串传进去,就能生成对应的go的结构体
- 用生成的结构体获取到返回的response body数据,反序列化并直接打印:
- 六、将打印内容改为需求中需要打印的信息
- 七、获取该进程(main方法)的变量,取第二个作为参数word,传入打印方法
3)实现SOCKS5代理:
* 小demo:
- 需求:创建一个基于tcp连接的服务(本机的xxx端口),读取用户端发送的报文(如字符串),返回相同的字符串
- ==重点==:怎么实现tcp端口,开放并获取请求的字符串,并处理和打印出来
四、==语言进阶 - 协程==
1)协程:Goroutine
- 并发:一个核,多线程抢夺时间片
- 并行:多个核,多线程一起运行 -> Go能充分发挥多核优势
- 线程:属于内核态,系统级别,它的创建等操作会重很多
- ==协程==(Goroutine):属于用户态,它由go创建和调度,操作轻(轻松应对上万协程)
- 方法:通过在函数前加上go关键字来为函数创建协程
2)协程间通信:channel
- CSP:通信与共享内存
- Go提倡通过通道来共享内存
- 无缓冲通道:直接传
- 有缓冲通道:规定队列中的元素数量,满了会有阻塞
- 通过通道共享内存的具体实现:
- 补充(不推荐):通过加锁实现并发的安全
3)WaitGroup:协程计算器
- 前面介绍协程用到的sleep不够优雅(可能出错),可以用WaitGroup更加精确的停止
- 代码:
五、==依赖管理==
1)Go Module介绍:
2)go.mod组成:
- ①go.mod的版本规则:
- ②直接依赖、间接依赖:
- ③incompatible:没有go.mod文件且主版本2+的依赖会有该后缀(表示可能有些代码不兼容)
3)依赖关系冲突:选择最低的兼容版本
4)依赖分发:Proxy
- 通过代理仓库来获取依赖:==修改GOPROXY变量实现==
5)go get工具、go mod工具:
六、==测试==
1)单元测试:
- 一、组成:
- 二、规则:
- Ps:如果测试方法不以大写Test开头,ide就不会出现运行的按钮提示
- 例:
- 结果:
- 三、使用第三方assert包进行校验
- 四、覆盖率
- 提高覆盖率:
- tips:代码设计时,函数应单一职责,这使得测试的单元粒度小,而覆盖率会更高
2)Mock
- 一、单元测试的要求
- 幂等:每次运行的结果应该一样
- 稳定:单元测试应该是相互隔离的,我们在任何时候都能运行
- 而一些复杂的依赖,比如数据库、cache等,由于网络等因素会造成一些问题 -> Mock机制
- 例:一些问题
- 函数依赖于一些本地的文件,一旦文件被修改,就不能正常地测试了
- 一、介绍mock包:monkey
- 打桩:
- 例:用Patch()打桩函数ReadFirstLine(),修改逻辑为直接返回值“line110”
3)基准测试:
- 概念:指测试代码的运行性能、cpu损耗等
- 例:
- 扩展:解决rand包性能差问题,介绍一个开源fastrand(适用大部分场景)