Golang初级系列教程-内存变量指针
来源:互联网 发布:java 文件上传原理 编辑:程序博客网 时间:2024/05/01 19:15
程序本身是利用存放在机器内存中的数据,并执行机器指令的一系列过程。以两数相加为例,这两个数据必须存在机器内存当中。而存放这两个数据的那部分内存区域,需要首先询问机器进行内存的分配。在Go
语言中,可以轻松的对大部分类型通过初始化操作实现。
例如如下代码:
package mainimport "fmt"func main() { i := 5 var j int fmt.Println("i is: ", i) fmt.Println("j is: ", j)}
i is: 5j is: 0
Go
会自动的为i
进行内存分配——分配一个整型大小空间的区域。在实例代码中,i := 5
说明在空间分配之后,数值5
便被塞到了那个空间中。对于变量j
,则没有分配任何值。然而,Go
会默认对大部分类型分配一个默认的zero-value
。对于数值变量而言,即为0
。
如下图,展示了内存现在的结构:
至此,i
的值为5
, j
的值为0
。
内置类型默认值
让我们举几个简短的例子,查看一下在Go
中已知类型的zero-value
或者说默认值。
代码如下:
package mainimport "fmt"func main() { var i int fmt.Println("default int is: ", i) var s string fmt.Println("default string is: ", s) var f float64 fmt.Println("default float64 is: ", f) var arInt [3]int fmt.Println("default int array is: ", arInt) var c complex64 fmt.Println("default complex64 is: ", c)}
default int is: 0default string is:default float64 is: 0default int array is: [0 0 0]default complex64 is: (0+0i)
内存地址
每个内存变量都对应一个实际的物理地址。许多编程语言,包括Go
,都允许通过地址访问数据。
如下代码:
package mainimport "fmt"func main() { i := 5 fmt.Println("i is: ", i) fmt.Println("address of i is: ", &i)}
i is: 5address of i is: 0xf840000040
注意上面的代码,通过&
符号,可以获取一个变量的实际物理地址。
让我们再多举几个栗子:
package mainimport "fmt"func main() { var i int fmt.Println("address of i is: ", &i) var s string fmt.Println("address of s is: ", &s) var f float64 fmt.Println("address of f is: ", &f) var c complex64 fmt.Println("address of c is: ", &c)}
address of i is: 0xf840000040address of s is: 0xf8400013e0address of f is: 0xf8400000f8address of c is: 0xf8400000f0
实际的地址输出,根据机器的不同而不同,同样的代码两次执行的输出结果也不同。因为,机器之后的内存布局不同,另外在程序执行时,每次都是动态分配的地址空间。
所以,你可能要问:由于不同的机器地址空间变化,那么程序是不是也会产生不同的结果?地址确实会产生变化,但是大多数程序不是使用实际的地址数值进行工作的。它们实际上是用的地址中所包含的数据。可以通过在地址前面添加*
获取地址内部保存的数值。让我们列举一些实例。
package mainimport "fmt"func main() { var i int fmt.Println("value of i is: ", i) fmt.Println("address of i is: ", &i) fmt.Println("value at address ", &i, " is: ", *(&i)) //value at (address of i) fmt.Println() var s string fmt.Println("value of s is: ", s) fmt.Println("address of s is: ", &s) fmt.Println("value at address ", &s, " is: ", *&s) ////value at address of i fmt.Println() var f float64 fmt.Println("value of f is: ", f) fmt.Println("address of f is: ", &f) fmt.Println("value at address ", &f, " is: ", *&f) fmt.Println() var c complex64 fmt.Println("value of c is: ", c) ptr := &c //address of c. fmt.Println("address of c is: ", ptr) fmt.Println("value at address ", ptr, " is: ", *ptr) //value at the address}
value of i is: 0address of i is: 0xf840000040value at address 0xf840000040 is: 0value of s is: address of s is: 0xf8400013b0value at address 0xf8400013b0 is: value of f is: 0address of f is: 0xf8400000e8value at address 0xf8400000e8 is: 0value of c is: (0+0i)address of c is: 0xf8400000b8value at address 0xf8400000b8 is: (0+0i)
这种地址变量,成为指针。在上面的例子中 ptr := &c
, ptr
就是一个指针,它指向c
的地址空间,所以ptr
是变量c
的指针,可以认为ptr
是c
的一个引用。前面叙述的那些都能够正常运作,但是在使用时有些许区别。
如果,i := 5; ptr := &i
, 可以用下图粗劣的表示这种关系。使用时,i
和 *ptr
都表示整型数值5
。
指针必须指向一个变量,不能指向一个具体的数值或者静态变量,如下面的例子所示。
package mainfunc main() { const i = 5 ptr := &i //error: cannot take the address of i ptr2 := &10 //error: cannot take the address of 10}
地址/指针/引用的用图
为什么需要地址/指针/引用这么多复杂的设计?直接使用真实数值不就很好么?
第一个原因是效率问题。在后面讨论传值和传引用时会讲述更多的内容。让我们打个比方。例如在维基百科上的一篇内容,比如巴黎:http://en.wikipedia.org/wiki/Paris。现在我们想把整个内容都发送给某人,一种方式是将整篇内容拷贝下来,通过邮件或者打印稿的方式发送给他。一种更加快速和方便的方式是仅仅把链接——唯一的URL,发过去即可。通过这种方式,没有额外的拷贝,同时你们两个都能通过链接读取到最新的内容。第一种发送整篇内容的方式,就如同传值——传输全部的值*,只发送链接,如同传引用,实际上传输的只是地址。
上述两个方式根据场景不同各自都有有用之处。当传递引用时,实际的数据只有一份,所有的改动都是对原数据的改动。传值,则会产生多份拷贝,各自更改并不会相互影响。
Golang一种神奇的语言,让我们一起进步
- Golang初级系列教程-内存变量指针
- Golang初级系列教程-Struct
- Golang初级系列教程-接口
- Golang初级系列教程-安装配置
- Golang初级系列教程-常见错误
- Golang初级系列教程-控制结构-ifelse
- Golang初级系列教程-继承和子类
- Golang初级系列教程-多重继承
- Golang初级系列教程-接口2
- Golang初级系列教程-接口多态性
- Golang初级系列教程-面向对象总结
- Golang初级系列教程-手把手编写 Hello World
- Golang初级系列教程-控制结构-for-break-continue-range
- Golang初级系列教程-控制结构-switch-case
- Golang初级系列教程-控制结构-defer语句
- Golang初级系列教程-函数多个返回值
- Golang初级系列教程-结构体方法-Methods on structs
- 指针变量 初级
- Phoenix on HBase
- Spark 编程起步
- 把握十年
- BZOJ 4390: [Usaco2015 dec]Max Flow|树链剖分
- duilib : 在对话框中增加文件拖拽功能
- Golang初级系列教程-内存变量指针
- Linux+Apache+Mysql+Php源码安装
- 算法洗脑系列(8篇)——第七篇 动态规划
- ovirt-shell 使用
- [Read Paper] Improving neural networks by preventing co-adaptation of feature detectors
- WIN7 JDK 环境变量配置
- spring 事务 Transactional
- 优化win7内存获取管理员权限压缩winsx文件夹
- 利用Fragment实现仿微信Tab效果(Fragment的初步学习)