Go 运行期加载 C 动态库(Linux版)

前面写的一篇 Go 调用 C 写的动态库完整例子(Linux版),是在告诉编译器用 /* #cgo ...*/ 的方式去加载动态库 libadd.so,这让代码丧失了一定的灵活性,比如同样的函数由多个动态库提供了不同的实现。这就需要做到在 Go 程序中可根据不同的输入条件选择不同的动态库实现,大概是

if 条件1 {
    loadLibrary("libadd1.so")
    调用其中的实现函数 add
else if 条件 2 {
    loadLibrary("libadd2.so")
    调用其中的实现函数 add
else {
    loadLibrary("libaddx.so")
    调用其中的实现函数  add

当然上面那样写是不行的,首先每一个动态库应该在程序运行期间只加载一次,定位的函数应该要缓存起来复用。 阅读全文 >>

Go 语言使用 Go Modules(go.mod) 来管理依赖

前几日系统性差不多读完了一本讲解 Go 语言的书籍,记录下几篇笔记,现在终于能够开始看看专题性的知识了。首先就是关于 Go 如何管理依赖的问题,Java 经历了最早逐个下载  jar  包,到现在用 maven 来描述项目依赖,及进行项目的构建。而 Go 的起点还是要高一些,从一开始就有  go get, go install 命令来从中心库下载依赖。但管理多版本依赖是个问题,也没有明确的方式来怎么描述一个项目的依赖。

因此也就产生过一些第三方的 Go 依赖管理

  1. Glide(使用 glide.yaml 文件描述依赖)
  2. Godep (长时间没维护的项目)
  3. govendor (不再维护了,在 Go modules 出来后也不被推荐使用)
  4. 还有其他的 GPM, gb, gom, gvt 等都相继退出了历史的舞台

也就是说 Go Modules 才是王道,在理解 Go Modules 之前也许有必要了解一下传统 GOPATH 管理依赖的方式,其他第三方的管理工具用不着去学习了,早已成了云烟。

Go 语言首次在  1.11 版本中引进了 Go Modules, 在这之前或者没有启用 GO111MODULE 的话,我们用 go get 或 go install 来下载依赖,编译器会从 GOPATH 和 vendor 文件夹中查找包。 阅读全文 >>

Go 调用 C 写的动态库完整例子(Linux版)

总有那么一些老的,或高效的库是用 C/C++ 实现的,于是在其他语言中如果使用动态共享库就成了个问题。Java 要调用动态库需要用 JNI, 更快捷的话可使用第三方包装好的 JNI 调用库。在 Java 中要映射 C/C++ 的类型麻烦些,因为 Java 没有指针类型,所以从这方面来讲 Go 调用动态库幸许会更简单些。

下面我们自己在 Linux 下做一个动态库(.so 文件  - Shared Object),然在用 Go 来使用它。本文所用的操作系统为 Ubuntu20.04, 以 gcc  作为编译器。动态库的生成过程参考自 Linux动态库生成与使用指南 阅读全文 >>

Go 语言新手笔记(五)

终于来到的 Go 的网络编程了,来写一个 TCP 服务端与客户端的程序。要用到 Go 语言的  net 包,是一个标准的 Listen+Accept 结构, 下面是一个简单的 TCP Server/Client 端的例子,启动了 Server 端口,可以用 telnet 去连接,也可以用 client.go 来连接 阅读全文 >>

Go 语言新手笔记(四)

学到了 Go 语言本身的语法之后,开始步入 Go 的应用部分,掌握一个语言不得不接触的就是它对文件,网络的操作。

在正式进入主题之前不得不抱怨一下 Go 的官方编码规范中的代码缩进格式。曾经 Google 出的 Java 缩进规范是用两个空格(通常是用四个空格),并且是杜绝用  Tab 进行缩进的,因为 Tab 的宽度是不很确定的。

然而 Google 建议 Go 的代码格式化工具  gofmt 却反常规的强制使用 Tab 进行缩进,而且是。本人用 IntelliJ IDEA 编写 Go, 即使在 Go 的 Code Style 中把 Use tab character 去掉也是用 Tab 缩进,原因是在 Code Style > Go 的  Other 中有项 Run gofmt [] On code reformat, 这项也不能勾选。

不明白 go fmtgofmt 为何强势而无理的用 Tab 进行缩进,看到多数地方以 8 个空格来显示一个  Tab,实在是难看,像下面这样子的 阅读全文 >>

Go 语言新手笔记(三)

终于要开始了解 Go 的结构体和接口了。Go 的结构体只是一种纯粹的数据类型,而不像 C/C++ 的结构体里还能添加方法。Go 的 struct 更像是 Python 的 dataclass, 或 Java 的 record。Go 的结构体是值类型,通过 new 函数来创建,在 C/C++ 中,只要是 new 得到的就是指针。

结构体的字段名称也可以用 _, 相当一个点位填充,字段也可以只有类型没有名称,称之为匿名字段。 阅读全文 >>

Go 语言新手笔记(二)

Go 语方的数组声明方式别具一格,把 [] 看得太重了,看下面的各种声明方式

再次强调 Go 的数组是值类型,作为函数参数传递会产生副本。避免传入数组产生副本消耗过多内存,办法是可传数组指针或用切片,切片是第一选择。

数组的大小最大为 2GB,用 ==!= 比较两个数组时它们必须类型和长度一致。 阅读全文 >>

Go 语言新手笔记(一)

Go 语言 2009 年面世,几个成功项目 Docker, Kubernetes, etcs, consul, flannel, 还有 Terraform。Go 编译运行快,听说学习也不难。

安装好 Go 后,有两个环境变量很重要, GOPATH 是工作目录,GOROOT 是 Go 的安装目录, 如 /usr/local/go。GOPATH 允许多个目录,用 : 或 ;(Windows 下) 分隔,当 GOPATH 有多个目录,go get 命令的包放在第一个目录下。

$GOPATH 目录中约定的三个子目录

  1. src: 存放 .go, .c, .h, .s 等源码文件,go run, go install 等命令也要在该目录下执行
  2. pkg: 存放编译时生成的中间文件,如 .a
  3. bin: 存放编译后的可执行文件 

Go 编程是声明了不用的全局变量是绝对的罪过,编译这一关过不了。Go 用 var 声明变量,如 var b bool = true。Go 有精确长度的丰富的基本类型,如 int8, int16, int32, int64, unit8, float32(6位精度), float64(15位精度) 等,单纯写成  int, unit 时,长度与系统有关。Go 的字符串用 UTF-8 格式编码的 Unicode 字符,每个字符对应一个 rune 类型,rune 是字符的意思,相当于 int32. 阅读全文 >>