Go入门笔记 / Go beginner
Go入门笔记
Go是编译型语言:
Go 代码通过 go build 或 go run 等命令来编译成二进制文件。尽管 Go 允许使用 go run 直接执行代码,但背后其实是先将代码编译成二进制文件再执行,而非逐行解释执行。
Go语言常用的命名规范
在 Go 中,导出的(exported)函数名应该以大写字母开头,而 未导出的(unexported)函数名则以小写字母开头。
- Hello: 这是一个导出的函数(首字母大写),因此它可以被包外的代码调用。导出的函数应该遵循 Go 的首字母大写命名规则。
- randomFormat: 这是一个未导出的函数(首字母小写),只能在当前包内使用。未导出的函数名通常首字母小写。
Tutorial: Get started with Go
When you need your code to do something that might have been implemented by someone else, you can look for a package that has functions you can use in your code.
Tutorial: Create a Go module
1. Relation between module and package
In a module, you collect one or more related packages for a discrete and useful set of functions.
2. How to name a module
A module's name should look like this:
<prefix>/<descriptive-text>
The prefix is typically a string that partially describes the module, such as a string that describes its origin. This might be:
The location of the repository where Go tools can find the module’s source code (required if you’re publishing the module).
For example, it might be github.com/<project-name>/.
Use this best practice if you think you might publish the module for others to use. For more about publishing, see Developing and publishing modules.
If you’re not using a repository name, be sure to choose a prefix that you’re confident won’t be used by others. A good choice is your company’s name. Avoid common terms such as widgets, utilities, or app.
For the descriptive text, a good choice would be a project name. Remember that package names carry most of the weight of describing functionality. The module path creates a namespace for those package names.
3. 常见占位符和字符串表示
- %v:%v 是最常用的占位符之一,它会根据值的类型来选择最合适的格式进行输出。它可以用于任何类型的数据(int、float、string、struct、slice 等)。对于复合类型(如结构体),%v 会输出字段值的默认格式。如果你想要更详细的输出,可以使用 %+v,这会在输出时包含字段名。
%q
:用于格式化字符串,表示带有双引号的字符串。例如:"Hello"
。%#q
:格式化成带有转义的字符串,并且带上双引号。与%q
相比,%#q
会转义所有不可打印的字符,例如换行符、制表符等。
另外,如果要打印的目标字符串当中含有双引号,那么可以使用反引号`来包围目标字符串,避免冲突。
而且,反引号包含的字符串是原始字符串,内部的字符都会被逐字解释,不会被转义。
Python当中,双引号和单引号都能用来表示字符串,但是Go当中只能用双引号;
Go中单引号只能用来表示单个字符,Go中单个字符的数据类型是rune,本质上是int32的别名;而C语言中char是int8。
示例:
want := regexp.MustCompile(`\b` + name + `\b`)
这里我们定义了一个正则表达式want,假设name变量是zzf,那么我们在括号里得到的就是`\bzzf\b`,当正则表达式引擎接受到这个字符串时,\字符被解析为转义字符,把b转义成:word boundary
4. 命名空间
每个package都是一个独立的命名空间,使用来自其他module中的函数时,要在函数名前加上相应package的限定,类似于C++的命名空间。
5.Go的指针
Go 和 C 语言中的指针对比
1. 基本概念(相同点)
- Go 和 C 都支持指针:
- 在 Go 和 C 中,指针都是用于存储另一个变量的内存地址。
- 通过指针,你可以间接访问或修改指向的变量的值。
- 获取指针和解引用:
- 在 Go 和 C 中,符号
&
用于获取变量的地址,符号*
用于通过指针访问变量的值。
Go 示例:
var a int = 10
var p *int = &a // p 是一个指向 a 的指针
fmt.Println(*p) // 解引用 p,输出 a 的值,即 10
C 示例:
int a = 10;
int *p = &a; // p 是一个指向 a 的指针
printf("%d\n", *p); // 解引用 p,输出 a 的值,即 10
2. 主要区别
1. 没有指针运算
Go: Go 不允许对指针进行算术运算。例如,不能对指针进行 p++
或 p--
这样的操作。
C: C 允许指针运算,能够通过指针运算遍历数组、内存块等。这在 C 中是一个重要的特性,用于内存管理和数组操作。
C 示例:
int arr[3] = {1, 2, 3};
int *p = arr;
p++; // 通过指针算术运算访问下一个元素
printf("%d\n", *p); // 输出 2
Go 示例:
var arr = [3]int{1, 2, 3}
var p *int = &arr[0]
p++ // 编译错误:Go 不支持指针运算
2. 安全性
Go: Go 语言在设计时更加关注内存安全,自动管理内存,并且有垃圾回收机制。指针操作受到更多的限制,防止出现像 C 中常见的悬空指针(dangling pointer)和内存泄漏等问题。
C: C 语言中,指针的使用更加灵活,但也更容易出错,导致内存泄漏、野指针等问题。C 中的内存管理是手动的,程序员需要负责释放动态分配的内存。
3. 垃圾回收
Go: Go 有自动垃圾回收机制,程序员不需要手动释放内存,指针所指向的对象在没有任何引用后会被垃圾回收。
C: C 没有垃圾回收,程序员需要使用 malloc
或 calloc
动态分配内存,并在不需要时使用 free
手动释放内存。否则,会造成内存泄漏。
4. 零值指针
Go: Go 中的指针类型有一个默认的零值 nil
,表示这个指针没有指向任何对象。Go 中的 nil
类似于 C 中的 NULL
,但 Go 提供了对 nil
的更严格检查。
C: C 中未初始化的指针是一个悬空指针,它没有指向任何有效的内存地址。虽然 C 中也有 NULL
表示空指针,但未初始化的指针容易引发问题。
Go 示例:
var p *int // 默认值是 nil
if p == nil {
fmt.Println("Pointer is nil")
}
C 示例:
int *p; // p 是一个未初始化的悬空指针
if (p == NULL) {
printf("Pointer is NULL\n");
}
5. 传递指针的方式
Go: Go 在函数参数传递中默认是值传递。如果你想修改传入的值,必须使用指针。
C: C 也有类似的值传递和指针传递的机制。通过指针传递变量地址可以在函数内部修改变量的值。
Go 示例:
func increment(val *int) {
*val++
}
var a = 5
increment(&a)
fmt.Println(a) // 输出 6
C 示例:
void increment(int *val) {
(*val)++;
}
int a = 5;
increment(&a);
printf("%d\n", a); // 输出 6
3. 小结
特性 | Go | C |
---|---|---|
指针运算 | 不支持指针运算 | 支持指针运算,例如 p++ , p-- |
内存管理 | 自动垃圾回收,无需手动释放 | 手动管理内存,使用 malloc/free |
指针初始化 | 未初始化的指针默认为 nil |
未初始化指针可能导致悬空指针 |
内存安全性 | 严格的内存安全检查 | 指针操作容易导致内存泄漏和野指针 |
传递指针修改变量 | 通过指针传递引用并修改 | 通过指针传递引用并修改 |
总结来说,Go 语言在指针的设计上更加简洁、安全,减少了直接操作内存的复杂性,并自动管理内存,避免了许多 C 语言中常见的内存管理问题。而 C 语言中的指针功能更为灵活,但同时也更容易出现内存相关的错误。
6.编写测试
Go的测试文件有命名规范:
需要以_test.go结尾。
Go的测试函数有命名规范:
标准形式为:TestName。
其中,Name用来描述它测试什么。
且所有的测试函数都要传入一个测试指针,例如:
func TestHelloName(t *testing.T)
结束