Go语言及快速入门

土豆仙

共 8150字,需浏览 17分钟

 ·

2021-05-28 22:57

   最近没啥时间,只能找点简单的新东西看看,这次简单总结一下这两年火热的新语言Go。

   其实早在18年,就开始对Go了有关注,却没太上心,只是简单的学了下语法,写简单的Demo,因为那时的Go真谈不上有什么好的。连基本的包管理都没做好。

    而现在嘛,Go粉,Go吹是真的不少。主要原因无非Java人才太多了,导致Go的优点能吹,Go的缺点修饰一下也能吹。

  而我对Go的关注,无非就是Docker、K8s,以及非常多的基础服务,比如数据存储、网络工具都Go写。不说其他项目,单Docker项目,就足够优秀、亮眼,你就会好奇写出这么优秀的项目的语言是不是也如此优秀。

放一张云生态全景图:


    然而,我不是Go吹,只会根据我仅有的知识体系,谈谈我的主观感受。

相对于JavaGo有非常多的反人类设计:异常、泛型(改进,新版本支持)、包管理(现在加强了很多)、不支持重载(不知道作者怎么想的,这个让人很头疼);优点也很明显:直接打包成可执行文件(作用并没那么大)云原生(并非非Go不行)、cgo调用底层c语言库(网上说要踩很多坑,不如python集成好)tag标签(类似Java注解)、函数作为一等公民、支持多返回值、Goroutine的轻量级;谈不上好坏的一些争议的点:部分语法习惯比如命名和类型非要倒置(哗众取宠)、比如方法这种显示写接收者、比如有人喜欢结构体有人喜欢类。
1

知识需要凝结成块,零散的知识需要系统的总结,才能慢慢变成有用。


01


Go语言快速入门


1.基础

优秀入门书:https://books.studygolang.com/gopl-zh/

基础语法笔记:http://www.topgoer.com

(详细讲解-略)

Go工具集

build 、doc 、env、fmt、get、install、list 、run、test 、version、vet   


2.内置库学习

库文档:https://studygolang.com/pkgdoc

1.fmtfmt包实现了类似C语言printfscanf的格式化I/O。主要分为向外输出内容和获取输入内容两大部分。常用输入函数:Scan、Scanf、Scanln,可以在程序运行过程中从标准输入获取用户的输入。常用输出函数Print、Printf、Println:直接输出内容Sprint、Sprintf、Sprintln:生成内容并返回字符串Fprint:将内容输出到一个io.Writer接口类型的变量,经常用于写入文件Errorf:根据format参数生成格式化字符串并返回一个包含该字符串的错误
占位符:// 通用verbs%v  值的默认格式%+v  类似%v,但输出结构体时会添加字段名%#v    Go语法表示值%T    Go语法表示类型%%   百分号表示// 浮点数%t   truefalse// 整数%b 表示二进制%c 该值对应的unicode吗值%d 表示十进制%o 表示八进制%q 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示%x 表示为十六进制,使用a-f%X 表示为十六进制,使用A-F%U 表示为Unicode格式:U+1234,等价于”U+%04X”// 浮点数与复数%b 无小数部分、二进制指数的科学计数法,如-123456p-78;参见strconv.FormatFloat%e 科学计数法,例如 -1234.456e+78%E 科学计数法,例如 -1234.456E+78%f 有小数点而无指数,例如 123.456%F 等价于%f%g 根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)%G 根据实际情况采用%E或%F格式(以获得更简洁、准确的输出// string与[]byte%s 输出字符串表示(string类型或[]byte)%q 双引号围绕的字符串,由Go语法安全地转义%x 十六进制,小写字母,每字节两个字符 (使用a-f)%X 十六进制,大写字母,每字节两个字符 (使用A-F)// Slice%p 切片第一个元素的指针// point%p 十六进制内存地址,前缀ox

2.Time 时间和日期 now := time.Now() //获取当前时间 year := now.Year() //年 month := now.Month() //月 day := now.Day() //日 hour := now.Hour() //小时 minute := now.Minute() //分钟 second := now.Second() //秒    timestamp1 := now.Unix()     //时间戳 timestamp2 := now.UnixNano() //纳秒时间戳 ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器 3.Flag Go语言内置的flag包实现了命令行参数的解析,flag包使得开发命令行工具更为简单。4.Log Go语言内置的log包实现了简单的日志服务。5.IO操作os包提供了Create、NewFile、Open、OpenFile、Remove方法返回的文件对象,提供了读写方法,比如Write、WriteAt、WriteString、Read、ReadAt方法bufio包实现了带缓冲区的读写,是对文件读写的封装6.Strconv strconv包实现了基本数据类型与其字符串表示的转换,主要有以下常用函数:Atoi()、Itia()、parse系列、format系列、append系列。7.Template html/template包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。它提供了和text/template包相同的接口,Go语言中输出HTML的场景都应使用text/template包。8.Http(重点) Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。9.Context Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理。请求处理函数通常会启动额外的 goroutine 用来访问后端服务,比如数据库和RPC服务。用来处理一个请求的 goroutine 通常需要访问一些与请求特定的数据,比如终端用户的身份认证信息、验证相关的token、请求的截止时间。当一个请求被取消或超时时,所有用来处理该请求的 goroutine 都应该迅速退出,然后系统才能释放这些 goroutine 占用的资源。10.jaonjson可以和map、struct相互转换11.reflect反射可以获取interface类型信息、获取值信息、修改值信息反射可以查看结构体字段、类型、方法,修改结构体的值,调用方法空接口 可以表示任何参数,利用反射判断参数类型获取类型信息:reflect.TypeOf,是静态的获取值信息:reflect.ValueOf,是动态的



3.项目目录结构

  一个好的目录规范才能让代码组织清晰,明白通用目录规范也才能看得懂别人的代码

目录/cmd该项目的主要应用。每个应用程序的目录名称应与您想要的可执行文件的名称相匹配(例如/cmd/myapp)。如果您认为代码可以导入并在其他项目中使用,那么它应该存在于/pkg目录中。如果代码不可重用或者您不希望其他人重用它,请将该代码放在/internal目录中。/internal私有应用程序和库代码。这是您不希望其他人在其应用程序或库中导入的代码。将您的实际应用程序代码放在/internal/app目录(例如/internal/app/myapp)和/internal/pkg目录中这些应用程序共享的代码(例如/internal/pkg/myprivlib)。/pkg可以由外部应用程序使用的库代码(例如/pkg/mypubliclib)。其他项目将导入这些库,期望它们可以工作,所以在你把东西放在这里之前要三思而后行:-)/vendor应用程序依赖项(手动管理或由您喜欢的依赖管理工具管理dep)。tip:如果要构建库,请不要提交应用程序依赖项。

服务应用程序目录/apiOpenAPI / Swagger规范,JSON模式文件,协议定义文件。请参阅/api目录以获取示例。
Web应用程序目录/web特定于Web应用程序的组件:静态Web资产,服务器端模板和SPA。
常见应用程序目录/configs配置文件模板或默认配置。将您的confd或consul-template模板文件放在这里。/init系统初始化(systemd,upstart,sysv)和进程管理器/主管(runit,supervisord)配置。/scripts脚本执行各种构建,安装,分析等操作。这些脚本使根级Makefile保持简洁(例如https://github.com/hashicorp/terraform/blob/master/Makefile)。请参阅/scripts目录以获取示例。/build包装和持续集成。将您的云(AMI),容器(Docker),OS(deb,rpm,pkg)包配置和脚本放在/build/package目录中。将CI(travis,circle,drone)配置和脚本放在/build/ci目录中。请注意,某些CI工具(例如,Travis CI)对其配置文件的位置非常挑剔。尝试将配置文件放在/build/ci将它们链接到CI工具所期望的位置的目录中(如果可能)。/deploymentsIaaS,PaaS,系统和容器编排部署配置和模板(docker-compose,kubernetes / helm,mesos,terraform,bosh)。/test其他外部测试应用和测试数据。您可以随意构建/test目录。对于更大的项目,有一个数据子目录是有意义的。例如,您可以拥有/test/data或者/test/testdata如果需要Go来忽略该目录中的内容。请注意,Go也会忽略以“。”开头的目录或文件。或“_”,因此您在命名测试数据目录方面具有更大的灵活性。请参阅/test目录以获取示例。
其他目录/docs设计和用户文档(除了你的godoc生成的文档)。请参阅/docs目录以获取示例。/tools该项目的支持工具。请注意,这些工具可以从/pkg和/internal目录中导入代码。请参阅/tools目录以获取示例。/examples应用程序和/或公共库的示例。请参阅/examples目录以获取示例。/third_party外部帮助工具,分叉代码和其他第三方实用程序(例如,Swagger UI)。/githooksGit钩子。/assets与您的存储库一起使用的其他资产(图像,徽标等)。/website如果您不使用Github页面,这是放置项目的网站数据的地方。请参阅/website目录以获取示例。
tip:你不应该有的目录/src

4.包管理工具

常见的包管理有,dep、go vendor、glide、go modules 等。

建议初步只看go mod,常用命令

go mod 命令go mod tidy拉取缺少的模块,移除不用的模块。我常用这个命令。go mod vendor将依赖复制到vendor下。我常用这个命令。go mod download下载依赖包。go mod verify检验依赖。go mod graph打印模块依赖图。其他命令,可以执行 go mod ,查看即可。


5.生态及常用框架

1.urfave/cli go语言的命令行库 =》同类型:cobra

github| clihttps://github.com/urfave/cligithub| cobrahttps://github.com/spf13/cobra

2. web框架 gin  =》同类型 Iris、 Echo 、 Beego

文档 | Gin Web Frameworkhttps://gin-gonic.com/zh-cn/docs/


3.加载配置文件 viper

https://github.com/spf13/viper#working-with-flags


4.casbin 轻量级访问控制框架

博客 | Casbinhttps://www.kancloud.cn/oldlei/casbin/1289455


5.日志Zap、Lumberjack(Zap本身不支持切割归档日志文件,使用Lumberjack进行日志切割归档)

文档 | zaphttps://pkg.go.dev/go.uber.org/zap


6.数据库 Gorm 类似Hibernate

文档| GORMhttps://gorm.io/zh_CN/


7.定时调度robfig

8.colly 爬虫

6.刷些练习-例如算法


题解:https://github.com/halfrost/LeetCode-Go
参考:https://books.halfrost.com/leetcode/
模板:https://github.com/greyireland/algorithm-pattern

7.web项目 go-admin

比较规范的web管理系统模板,并集成了时下流行组件:

https://github.com/go-admin-team/go-admin.git

✨ 特性    遵循 RESTful API 设计规范    基于 GIN WEB API 框架,提供了丰富的中间件支持(用户认证、跨域、访问日志、追踪ID等)    基于Casbin的 RBAC 访问控制模型    JWT 认证    支持 Swagger 文档(基于swaggo)    基于 GORM 的数据库存储,可扩展多种类型数据库    配置文件简单的模型映射,快速能够得到想要的配置    代码生成工具    表单构建工具    多命令模式    TODO: 单元测试


8.编译、打包、部署

(略)

9.优秀参考项目

web项目:go-admin、相册管理photoprism

明星项目:Docker(容器技术)、Kubernetes(容器编排)Prometheus(监控系统)、Etcd(分布式存储)、InfluxDB(时序数据库)

10.设计模式

参考别人如何组织设计模式https://github.com/senghoo/golang-design-pattern


02


Java和Go语言比较


   这里比较并非全面,仅仅挑自己写代码感兴趣的几点作为比较。Java在web服务开发方面的底蕴,Go是很难追赶的。而Go在云生态方面就比Java先走了很远。作为搬砖工,我是不屑关注太底层或者太宏观的泛泛概念,手里的干活家伙才是我需要日常吐槽讨论的东西。



1.并发编程

线程(Thread):有时被称作轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

协程(coroutine):又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。

线程与协程,表面上也很难就应用场景分好坏。


不过一句话听起来会让人对Go的并发感兴趣:一个Golang的程序中可以支持10w级别的Goroutine。



并发模型:Go实现了两种并发形式:

   第一种是大家普遍认知的:多线程共享内存。其实就是Java或者C++等语言中的多线程开发。

   非常典型的方式就是,在访问共享数据(例如数组、Map、或者某个结构体或对象)的时候,通过锁来访问,因此,在很多时候,衍生出一种方便操作的数据结构,叫做“线程安全的数据结构”。例如Java提供的包”java.util.concurrent”中的数据结构。Go中也实现了传统的线程并发模型。

   另外一种是Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。goroutine 奉行通过通信来共享内存,而不是共享内存来通信。

    Go的CSP并发模型,是通过goroutinechannel来实现的。在通信过程中,传数据channel <- data和取数据<-channel必然会成对出现,因为这边传,那边取,两个goroutine之间才会实现通信。而且不管传还是取,必阻塞,直到另外的goroutine传或者取为止。(本质上类似Java的同步阻塞队列)

2.反射

  反射本质上,是能让程序猿动态的拿到写死的程序逻辑,进而可选择性作进一步处理,或者进行配置化执行逻辑。

  1.  Go反射比Java反射使用上简单。

  2.  Java提供了setAccessible方法来获取操作私有字段和私有方法的权限,而Golang未提供类似机制,因此Golang无法通过反射来操作私有字段和私有方法。想实现一个接口,直接实现接口包含的方法,不用关心方法属于哪个接口。

3.语言特性

1.在语言层面,Go不支持继承、不支持重载,导致诸多不便。

2.Java侵入式接口:需要显式地创建一个类去实现一个接口,Go非侵入式接口:不需要显式地创建一个类去实现一个接口。(不需要再语法上显式地声明,貌似没什么实际差别,用得着用侵入式这个词?)

    go不支持继承,在 Go 中, 使用组合和内嵌实现代码的复用, 使用接口来实现多态和动态绑定。但是不支持重载,目前没看到好的办法,莫非,仅仅因为参数类型不同,就要实现一个新的名称的函数,或者在函数内部根据参数进行不同逻辑处理(这样属于硬编码!)?



总体而言,Go近些年,进步还是神速的,将来未必不能成为Java强劲的竞争对手。


浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报