mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-17 11:14:20 +08:00
fix typo and optimize.
Change-Id: I7b6938936231fd722814984678ffa30402539fd9
This commit is contained in:
@@ -27,7 +27,7 @@ func | 1个机器字
|
||||
chan | 1个机器字
|
||||
interface | 2个机器字(type,value)
|
||||
|
||||
Go语言的规范并没有要求一个字段的声明顺序和内存中的顺序是一致的,所以理论上一个编译器可以随意地重新排列每个字段的内存位置,随然在写作本书的时候编译器还没有这么做。下面的三个结构体虽然有着相同的字段,但是第一种写法比另外的两个需要多50%的内存。
|
||||
Go语言的规范并没有要求一个字段的声明顺序和内存中的顺序是一致的,所以理论上一个编译器可以随意地重新排列每个字段的内存位置,虽然在写作本书的时候编译器还没有这么做。下面的三个结构体虽然有着相同的字段,但是第一种写法比另外的两个需要多50%的内存。
|
||||
|
||||
```Go
|
||||
// 64-bit 32-bit
|
||||
|
||||
@@ -56,7 +56,7 @@ pT := uintptr(unsafe.Pointer(new(T))) // 提示: 错误!
|
||||
|
||||
在编写本文时,还没有清晰的原则来指引Go程序员,什么样的unsafe.Pointer和uintptr的转换是不安全的(参考 [Issue7192](https://github.com/golang/go/issues/7192) ). 译注: 该问题已经关闭),因此我们强烈建议按照最坏的方式处理。将所有包含变量地址的uintptr类型变量当作BUG处理,同时减少不必要的unsafe.Pointer类型到uintptr类型的转换。在第一个例子中,有三个转换——字段偏移量到uintptr的转换和转回unsafe.Pointer类型的操作——所有的转换全在一个表达式完成。
|
||||
|
||||
当调用一个库函数,并且返回的是uintptr类型地址时(译注:普通方法实现的函数不尽量不要返回该类型。下面例子是reflect包的函数,reflect包和unsafe包一样都是采用特殊技术实现的,编译器可能给它们开了后门),比如下面反射包中的相关函数,返回的结果应该立即转换为unsafe.Pointer以确保指针指向的是相同的变量。
|
||||
当调用一个库函数,并且返回的是uintptr类型地址时(译注:普通方法实现的函数尽量不要返回该类型。下面例子是reflect包的函数,reflect包和unsafe包一样都是采用特殊技术实现的,编译器可能给它们开了后门),比如下面反射包中的相关函数,返回的结果应该立即转换为unsafe.Pointer以确保指针指向的是相同的变量。
|
||||
|
||||
```Go
|
||||
package reflect
|
||||
|
||||
@@ -101,7 +101,7 @@ func NewWriter(out io.Writer) io.WriteCloser {
|
||||
}
|
||||
```
|
||||
|
||||
在预处理过程中,cgo工具为生成一个临时包用于包含所有在Go语言中访问的C语言的函数或类型。例如C.bz_stream和C.BZ2_bzCompressInit。cgo工具通过以某种特殊的方式调用本地的C编译器来发现在Go源文件导入声明前的注释中包含的C头文件中的内容(译注:`import "C"`语句前仅挨着的注释是对应cgo的特殊语法,对应必要的构建参数选项和C语言代码)。
|
||||
在预处理过程中,cgo工具为生成一个临时包用于包含所有在Go语言中访问的C语言的函数或类型。例如C.bz_stream和C.BZ2_bzCompressInit。cgo工具通过以某种特殊的方式调用本地的C编译器来发现在Go源文件导入声明前的注释中包含的C头文件中的内容(译注:`import "C"`语句前紧挨着的注释是对应cgo的特殊语法,对应必要的构建参数选项和C语言代码)。
|
||||
|
||||
在cgo注释中还可以包含#cgo指令,用于给C语言工具链指定特殊的参数。例如CFLAGS和LDFLAGS分别对应传给C语言编译器的编译参数和链接器参数,使它们可以特定目录找到bzlib.h头文件和libbz2.a库文件。这个例子假设你已经在/usr目录成功安装了bzip2库。如果bzip2库是安装在不同的位置,你需要更新这些参数(译注:这里有一个从纯C代码生成的cgo绑定,不依赖bzip2静态库和操作系统的具体环境,具体请访问 https://github.com/chai2010/bzip2 )。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 第13章 底层编程
|
||||
|
||||
Go语言的设计包含了诸多安全策略,限制了可能导致程序运行出现错误的用法。编译时类型检查检查可以发现大多数类型不匹配的操作,例如两个字符串做减法的错误。字符串、map、slice和chan等所有的内置类型,都有严格的类型转换规则。
|
||||
Go语言的设计包含了诸多安全策略,限制了可能导致程序运行出错的用法。编译时类型检查可以发现大多数类型不匹配的操作,例如两个字符串做减法的错误。字符串、map、slice和chan等所有的内置类型,都有严格的类型转换规则。
|
||||
|
||||
对于无法静态检测到的错误,例如数组访问越界或使用空指针,运行时动态检测可以保证程序在遇到问题的时候立即终止并打印相关的错误信息。自动内存管理(垃圾内存自动回收)可以消除大部分野指针和内存泄漏相关的问题。
|
||||
|
||||
@@ -8,11 +8,11 @@ Go语言的实现刻意隐藏了很多底层细节。我们无法知道一个结
|
||||
|
||||
总的来说,Go语言的这些特性使得Go程序相比较低级的C语言来说更容易预测和理解,程序也不容易崩溃。通过隐藏底层的实现细节,也使得Go语言编写的程序具有高度的可移植性,因为语言的语义在很大程度上是独立于任何编译器实现、操作系统和CPU系统结构的(当然也不是完全绝对独立:例如int等类型就依赖于CPU机器字的大小,某些表达式求值的具体顺序,还有编译器实现的一些额外的限制等)。
|
||||
|
||||
有时候我们可能会放弃使用部分语言特性而优先选择更好具有更好性能的方法,例如需要与其他语言编写的库互操作,或者用纯Go语言无法实现的某些函数。
|
||||
有时候我们可能会放弃使用部分语言特性而优先选择具有更好性能的方法,例如需要与其他语言编写的库进行互操作,或者用纯Go语言无法实现的某些函数。
|
||||
|
||||
在本章,我们将展示如何使用unsafe包来摆脱Go语言规则带来的限制,讲述如何创建C语言函数库的绑定,以及如何进行系统调用。
|
||||
|
||||
本章提供的方法不应该轻易使用(译注:属于黑魔法,虽然可能功能很强大,但是也容易误伤到自己)。如果没有处理好细节,它们可能导致各种不可预测的并且隐晦的错误,甚至连有经验的的C语言程序员也无法理解这些错误。使用unsafe包的同时也放弃了Go语言保证与未来版本的兼容性的承诺,因为它必然会在有意无意中会使用很多实现的细节,而这些实现的细节在未来的Go语言中很可能会被改变。
|
||||
本章提供的方法不应该轻易使用(译注:属于黑魔法,虽然功能很强大,但是也容易误伤到自己)。如果没有处理好细节,它们可能导致各种不可预测的并且隐晦的错误,甚至连有经验的的C语言程序员也无法理解这些错误。使用unsafe包的同时也放弃了Go语言保证与未来版本的兼容性的承诺,因为它必然会有意无意中使用很多非公开的实现细节,而这些实现的细节在未来的Go语言中很可能会被改变。
|
||||
|
||||
要注意的是,unsafe包是一个采用特殊方式实现的包。虽然它可以和普通包一样的导入和使用,但它实际上是由编译器实现的。它提供了一些访问语言内部特性的方法,特别是内存布局相关的细节。将这些特性封装到一个独立的包中,是为在极少数情况下需要使用的时候,同时引起人们的注意(译注:因为看包的名字就知道使用unsafe包是不安全的)。此外,有一些环境因为安全的因素可能限制这个包的使用。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user