This commit is contained in:
Unknown
2013-06-18 14:01:24 +08:00
parent 0a8c1b30bf
commit 25a93184a3
3 changed files with 38 additions and 35 deletions

View File

@@ -8,7 +8,7 @@
该翻译版本已获得原作者Ivo Balbaert本人授权并表示支持开源事业的发展
##翻译进度
4.8 [时间和日期](eBook/04.8.md)
4.9 [指针](eBook/04.9.md)
##支持本书
如果你喜欢本书《Go入门指南》你可以参与到本书的翻译或纠正工作中来具体请联系【无闻 E-mailjoe2010xtmf#163.com】一同完善本书并帮助壮大 Go 语言在国内的学习群体,给大家提供更好的学习资源。

View File

@@ -1,43 +1,44 @@
#4.9 指针
不像 Java 和 .NETGo 语言为程序员提供了控制数据结构的指针的能力但是你不能进行指针运算。通过给予程序员基本内存布局Go 语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。
不像 Java 和 .NETGo 语言为程序员提供了控制数据结构的指针但是你不能进行指针计算。通过给程序员控制基本内存布局Go 语言允许你控制特定集合的数据结构,分配的数量,和内存访问模式,这些对构建性能良好的系统是非常重要的:如果你想要做的系统编程,操作系统和网络,指针对性能表现是非常重要且不可缺少的
由于各种原因,指针对于使用面向对象编程的现代程序员来说可能显得有些陌生,不过我们将会在这一小节对此进行解释,并在未来的章节中展开深入讨论
由于指针对当代面向对象编程的程序员是未知的,我们将在这里解释他们,并在接下来的章节中继续深入
程序在内存中存储它的值,每个内存块(或字)有一个地址,通常用十六进制数表示,如:`0x6b0820``0xf84001d7f0`
程序在内存中存储它的值,每个内存块(或词)有一个地址,通常用十六进制数表示,如 0x6b0820 或 0xf84001d7f0
Go 语言的取地址符是 `&`,放到一个变量前使用就会返回相应变量的内存地址。
Go 语言的地址操作符是 &,放到一个变量前,会返回我们这个变量的内存地址
如下的代码片段(参见 Listing 4.9 pointer.go输入如下例“An integer: 5, its location in memory: 0x6b0820这个值随着你每次运行程序而变化
下面的代码片段Example 4.9 [pointer.go](examples/chapter_4/pointer.go))可能输出 `An integer: 5, its location in memory: 0x6b0820`(这个值随着你每次运行程序而变化)
var i1 = 5
fmt.Printf(“An integer: %d, its location in memory: %p\n”, i1, &i1)
这个地址可以存储在一个叫指针的特殊数据类型中,在本例中这是一个指向 int 的指针,这里是 i1这里使用 *int 表示。如果我们想调用指针 intP我们可以这样声明它
这个地址可以存储在一个叫指针的特殊数据类型中,在本例中这是一个指向 int 的指针,`i1`:此处使用 *int 表示。如果我们想调用指针 intP我们可以这样声明它
var intP *int
然后下面这样写是正确的intP = &i1, intP 指向 i1。
然后使用 `intP = &i1` 是合法的,此时 intP 指向 i1。
因为它声明了一个指针以 %p 这个格式化字符串表示
指针的格式化标识符为 `%p`
intP 存储了 i1 的内存地址;它指向了 i1 的位置,它引用了变量 i1。
一个指针变量可以包含另一个值内存地址它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值表明它的原始性或结构性; 在类型的值卡面加 * 号(前缀),这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。
**一个指针变量可以指向任何一个值内存地址** 它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值表明它的原始性或结构性;你可以在指针类型前面加 * 号(前缀)来获取指针所指向的内容,这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。
一个新的被定义的指针,当没有分配给它变量时,的值nil
一个指针被定义没有分配到任何变量时,的值`nil`
一个指针变量通常缩写为 ptr
一个指针变量通常缩写为 `ptr`
!!在一个表达式如 var p *type 总是在 * 号和指针名间留有一个空间 - var p*type 是语法正确的,但是在更复杂的表达式中,它容易被误认为是一个乘法表达式!!
**注意事项**
符号 * 可以放在一个指针前,如 *intP那么它将得到这个指针指向地址的值它被称为反引用或者 contents 或者间接引用)操作符;另一种说法是指针转移。
在书写表达式类似 `var p *type` 时,切记在 * 号和指针名称间留有一个空格,因为 `- var p*type` 是语法正确的,但是在更复杂的表达式中,它容易被误认为是一个乘法表达式!
对于多个变量 var 如下是正确的: var == *(&var)
符号 * 可以放在一个指针前,如 `*intP`,那么它将得到这个指针指向地址上所存储的值;这被称为反引用(或者内容或者间接引用)操作符;另一种说法是指针转移。
现在我们能理解整个的pointer.go程序和他的输出
对于任何一个变量 var 如下表达式都是正确的:`var == *(&var)`
Listing 4.21—[pointer.go](examples/chapter_4/pointer.go):
现在,我们应当能理解 pointer.go 中的整个程序和他的输出:
Example 4.21 [pointer.go](examples/chapter_4/pointer.go):
package main
import "fmt"
@@ -54,15 +55,15 @@ Listing 4.21—[pointer.go](examples/chapter_4/pointer.go):
An integer: 5, its location in memory: 0x24f0820
The value at memory location 0x24f0820 is 5
我们可以表示内存使用情况如下
我们可以用下图来表示内存使用情况:
![](images/4.4.9_fig4.4.png?raw=true)
string_pointer.go 我们展示了指针对string的例子。
程序 string_pointer.go 我们展示了指针对string的例子。
它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)
它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)
Listing 4.22[string_pointer.go](examples/chapter_4/string_pointer.go):
Example 4.22 [string_pointer.go](examples/chapter_4/string_pointer.go)
package main
import "fmt"
@@ -81,33 +82,35 @@ Listing 4.22—[string_pointer.go](examples/chapter_4/string_pointer.go):
Here is the string *p: ciao
Here is the string s: ciao
通过对 *p 赋另一个值来更改“对象”, s 也会更改。
通过对 *p 赋另一个值来更改“对象”,这样 s 也会随之更改。
内存示意图如下:
![](images/4.4.9_fig4.5.png?raw=true)
注意:你不能得到一个文字或常量的地址,如下代码片段:
**注意事项**
你不能得到一个文字或常量的地址,例如:
const i = 5
ptr := &i //error: cannot take the address of i
ptr2 := &10 //error: cannot take the address of 10
所以 Go 语言,和其他低级(系统)语言,如 C C++ D 语言一样,有指针的概念。但是对指针进行计算(称为指针运算,例如 pointer + 2, 移动指向字符串的字节数,或指向一个数组的位置),这样做在 C 语言里经常发生内存访问错误导致程序崩溃,为了语言的内存安全,在 Go 语言中是不允许的。Go 语言的指针更像引用,如 Java C# 和 VB.NET 。
所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,有指针的概念。但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如:`pointer+2`移动指针指向字符串的字节数数组的某个位置)是不允许的。Go 语言的指针保证了内存安全,更像是 JavaC# 和 VB.NET 中的引用
所以: c = *p++ 在 Go 语言的代码中是不允许的。
因此 `c = *p++` 在 Go 语言的代码中是不合法的。
一个指针的高级应用是你可以传递一个引用到一个变量(如一个函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,至少使用一个变量指向们,所以从它们被创建开始,他们的周期范围是独立的
指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向们,所以从它们被创建开始就具有相互独立的生命周期
另一方面(虽然不太可能),因为一个指针导致的间接引用(一个进程执行了另一个地址),频繁使用会导致性能下降。
另一方面(虽然不太可能),由于一个指针导致的间接引用(一个进程执行了另一个地址),指针的过度频繁使用会导致性能下降。
指针也可以指向另一个指针,并且这种可以任意深度的嵌套,导致你可以有多级的间接引用,但在大多数情况这会使你的代码结构不清晰。
指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数情况这会使你的代码结构不清晰。
如我们所见,在大多数情况下 Go 语言可以程序员轻松创建指针,并且隐藏间接引用,如自动反向引用。
如我们所见,在大多数情况下 Go 语言可以使程序员轻松创建指针,并且隐藏间接引用,如自动反向引用。
对一个空指针反向引用,如下面的 2 行(参见程序 testcrash.go是不合法的,并且会使程序崩溃:
对一个空指针反向引用是不合法的,并且会使程序崩溃:
Listing 4.23 [testcrash.go](examples/chapter_4/testcrash.go):
Example 4.23 [testcrash.go](examples/chapter_4/testcrash.go):
package main
func main() {
@@ -117,7 +120,7 @@ Listing 4.23 [testcrash.go](examples/chapter_4/testcrash.go):
// in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
// runtime error: invalid memory address or nil pointer dereference
问题 4.2列举 Go 语言中使用 * 号的所有用法
**问题 4.2** 列举 Go 语言中 * 号的所有用法
##链接
- [目录](directory.md)

View File

@@ -1,9 +1,9 @@
##啊哦,亲,你看得也太快了。。。还没翻译完呢 0 0
要不等到 ***2013 年 6 月 18 日*** 再来看看吧~~
要不等到 ***2013 年 6 月 20 日*** 再来看看吧~~
这里还有一些其它的学习资源噢~
- [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming):已更新至 [第11](https://github.com/Unknwon/go-fundamental-programming/blob/master/lecture10/lecture10.md)
- [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming):已更新至 [第12](https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture12.md)
- [《Go Web编程》](https://github.com/astaxie/build-web-application-with-golang)
神马?你说你不想学习?那好吧,去逛逛看看行情也行~