欢迎访问我的博客,目前从事Machine Learning,欢迎交流

【读书笔记&个人心得】第3章:编辑器、集成开发环境与其它工具

Go 调试

在合适的位置使用打印语句输出相关变量的值(print/println 和 fmt.Print/fmt.Println/fmt.Printf

在 fmt.Printf 中使用下面的说明符来打印有关变量的相关信息:

1.在合适的位置使用打印语句输出相关变量的值(print/println 和 fmt.Print/fmt.Println/fmt.Printf)。

2.在 fmt.Printf 中使用下面的说明符来打印有关变量的相关信息:

%+v 打印包括字段在内的实例的完整信息
%#v 打印包括字段和限定类型名称在内的实例的完整信息
%T 打印某个类型的完整说明

3.使用 panic() 语句(第 13.2 节)来获取栈跟踪信息(直到 panic() 时所有被调用函数的列表)。

4.使用关键字 defer 来跟踪代码执行过程(第 6.4 节)。

Go 构建程序

在大多数 IDE 中,每次构建程序之前都会自动调用源码格式化工具 gofmt(官方) 并保存格式化后的源文件

如果程序执行一切顺利并成功退出后,将会在控制台输出 Program exited with code 0

go build 编译自身包和依赖包
go install 编译并安装自身包和依赖包

1.作用
go build:用于测试编译包,在项目目录下生成可执行文件(有main包)。
go install:主要用来生成库和工具。一是编译包文件(无main包),将编译后的包文件放到 pkg 目录下($GOPATH/pkg)。二是编译生成可执行文件(有main包),将可执行文件放到 bin 目录($GOPATH/bin)。

  1. 相同点
    都能生成可执行文件

  2. 不同点
    go build 不能生成包文件, go install 可以生成包文件
    go build 生成可执行文件在当前目录下, go install 生成可执行文件在bin目录下($GOPATH/bin)

链接:https://juejin.cn/post/6844903938060222471

格式化源码文件

在命令行输入 gofmt –w program.go 会格式化该源文件的代码然后将格式化后的代码覆盖原始内容(如果不加参数 -w 则只会打印格式化后的结果而不重写文件);
-w 应该是 write 的意思

格式化所有 Go 源文件

gofmt -w *.go 会格式化并重写所有 Go 源文件;

格式化某个目录的 Go 源文件

gofmt map1 会格式化并重写 map1 目录及其子目录下的所有 Go 源文件

生成代码文档

godoc 工具会从 Go 程序和包文件中提取顶级声明的首行注释以及每个对象的相关注释,并生成相关文档。(其实是直接在命令行输出的)

go doc package 获取包的文档注释,例如:go doc fmt 会显示使用 godoc 生成的 fmt 包的文档注释。

go doc package/subpackage 获取子包的文档注释,例如:go doc container/list。

go doc package function 获取某个函数在某个包中的文档注释,例如:go doc fmt Printf 会显示有关 fmt.Printf() 的使用说明。

其他常用工具

安装和编译非标准库

go install 是安装 Go 包的工具,类似 npm install,主要用于安装非标准库的包文件,将源代码编译成对象文件

源码版本升级

go fix 用于将你的 Go 代码从旧的发行版迁移到最新的发行版,它主要负责简单的、重复的、枯燥无味的修改工作,如果像 API 等复杂的函数修改,工具则会给出文件名和代码行数的提示以便让开发人员快速定位并升级代码。Go 开发团队一般也使用这个工具升级 Go 内置工具以及 谷歌内部项目的代码。go fix 之所以能够正常工作是因为 Go 在标准库就提供生成抽象语法树和通过抽象语法树对代码进行还原的功能。该工具会尝试更新当前目录下的所有 Go 源文件,并在完成代码更新后在控制台输出相关的文件名称。

单元测试

go test 是一个轻量级的单元测试框架(第 13 章)

Go 性能

Go 语言的执行效率大约比 C++ 慢 20%
保守估计在相同的环境和执行目标的情况下,Go 程序比 Java 或 Scala 应用程序要快上 2 倍,并比这两门语言占用的内存降低了 70%

时下流行的语言大都是运行在虚拟机上,如:Java 和 Scala 使用的 JVM,C# 和 VB.NET 使用的 .NET CLR。
尽管虚拟机的性能已经有了很大的提升,但任何使用 JIT 编译器和脚本语言解释器的编程语言(Ruby、Python、Perl 和 JavaScript)在 C 和 C++ 的绝对优势下甚至都无法在性能上望其项背
PS:JIT (just-in-time compilation,即时编译)是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态解释。静态编译的程序在执行前全部被翻译为机器码,而动态解释执行的则是一句一句边运行边翻译

其实比较多门语言之间的性能是一种非常猥琐的行为,因为任何一种语言都有其所擅长和薄弱的方面。例如在处理文本方面,那些只处理纯字节的语言显然要比处理 Unicode 这种更为复杂编码的语言要出色的多。(UTF8分成单字节、双字节、三字节、四字节模式 。 UTF-8编码字符理论上可以最多到4个字节长。)

Go 和 Scala 之间具有更多的可比性(都使用更少的代码),而 C++ 和 Java 都使用非常冗长的代码。
Go 的编译速度要比绝大多数语言都要快,比 Java 和 C++ 快 5 至 6 倍,比 Scala 快 10 倍。
Go 的二进制文件体积是最大的(每个可执行文件都包含 runtime)。
在最理想的情况下,Go 能够和 C++ 一样快,比 Scala 快 2 至 3 倍,比 Java 快 5 至 10 倍。
Go 在内存管理方面也可以和 C++ 相媲美,几乎只需要 Scala 所使用的一半,是 Java 的五分之一左右。

与其他语言进行交互

FFI

“FFI” 的全名是 Foreign Function Interface,通常指的是允许以一种语言编写的代码调用另一种语言的代码

srandom

"srandom()"的 s 应该是 seed(种子)的意思

函数示例

var i int
C.uint(i) 		// 从 Go 中的 int 转换为 C 中的无符号 int
int(C.random()) // 从 C 中 random() 函数返回的 long 转换为 Go 中的 int

生成代码包

cgo 会替代 Go 编译器来产生可以组合在同一个包中的 Go 和 C 代码。在实际开发中一般使用 cgo 创建单独的 C 代码包

使用 cgo

cgo 是把 C 和 GO 混写,注意:
如果你想要在你的 Go 程序中使用 cgo,则必须在单独的一行使用 import "C" 来导入,一般来说你可能还需要 import "unsafe"
名称 "C" 并不属于标准库的一部分,这只是 cgo 集成的一个特殊名称用于引用 C 的命名空间。在这个命名空间里所包含的 C 类型都可以被使用,例如 C.uint、C.long 等等,还有 libc 中的函数 C.random() 等也可以被调用。

C 库函数导入

导入有特别的讲究,要在 import "C" 之前使用注释的形式导入 C 语言库(甚至有效的 C 语言代码),它们之间没有空行

// #include <stdio.h>
// #include <stdlib.h>
import "C"

字符串

C 当中并没有明确的字符串类型,如果你想要将一个 string 类型的变量从 Go 转换到 C 时,可以使用 C.CString(s);同样,可以使用 C.GoString(cs) 从 C 转换到 Go 中的 string 类型

示例

package rand

// #include <stdlib.h>
import "C"

func Random() int {
	return int(C.random())
}

func Seed(i int) {
	C.srandom(C.uint(i))
}

内存管理

o 的内存管理机制无法管理通过 C 代码分配的内存,开发人员需要通过手动调用 C.free 来释放变量的内存:

defer C.free(unsafe.Pointer(Cvariable))

这一行最好紧跟在使用 C 代码创建某个变量之后,这样就不会忘记释放内存了

package print

// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"

func Print(s string) {
	cs := C.CString(s)
	defer C.free(unsafe.Pointer(cs))
	C.fputs(cs, (*C.FILE)(C.stdout))
}

构建 cgo 包

package print

// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"

func Print(s string) {
	cs := C.CString(s)
	defer C.free(unsafe.Pointer(cs))
	C.fputs(cs, (*C.FILE)(C.stdout))
}

你可以在使用将会在第 9.5 节讲到的 Makefile 文件(因为我们使用了一个独立的包),除了使用变量 GOFILES 之外,还需要使用变量 CGOFILES 来列出需要使用 cgo 编译的文件列表。例如,示上面代码就可以使用包含以下内容的 Makefile 文件来编译,你可以使用 gomake 或 make:

include $(GOROOT)/src/Make.inc
TARG=rand
CGOFILES=\
c1.go\
include $(GOROOT)/src/Make.pkg

(我觉得那两条斜杠像正则,应该就是只要指定 编译 c1.go ,上下的应该不用动)

posted @ 2023-03-01 11:53  有蚊子  阅读(10)  评论(0编辑  收藏  举报