基本结构和基本数据类型

指针

不像 Java 和 .NET,Go 语言为程序员提供了控制数据结构的指针的能力;但是,你不能进行指针运算。
通过给予程序员基本内存布局,Go 语言允许你控制特定集合的数据结构、分配的数量以及内存访问模
式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是
系统编程、操作系统或者网络应用,指针更是不可或缺的一部分。

由于各种原因,指针对于使用面向对象编程的现代程序员来说可能显得有些陌生,不过我们将会在这一小
节对此进行解释,并在未来的章节中展开深入讨论。

程序在内存中存储它的值,每个内存块(或字)有一个地址,通常用十六进制数表示,如: 0x6b0820 或
0xf84001d7f0 。

Go 语言的取地址符是 & ,放到一个变量前使用就会返回相应变量的内存地址。
下面的代码片段(示例 4.9 pointer.go)可能输出 An integer: 5, its location in memory: 0x6b0820
(这个值随着你每次运行程序而变化)。

  1. var i1 =
  2. fmt.Printf("An integer: %d, it's location in memory: %p\n", i1, &i1)

这个地址可以存储在一个叫做指针的特殊数据类型中,在本例中这是一个指向 int 的指针,即 i1 :此处
使用 *int 表示。如果我们想调用指针 intP,我们可以这样声明它:

var intP *int

然后使用 intP = &i1 是合法的,此时 intP 指向 i1。(指针的格式化标识符为 %p )intP 存储了 i1 的内存地址;

它指向了 i1 的位置,它引用了变量 i1。一个指针变量可以指向任何一个值的内存地址 它指向那个值的内存地址,

在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,

可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上 * 号(前缀)

来获取指针所指向的内容,这里的* 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。

当一个指针被定义后没有分配到任何变量时,它的值为 nil
。一个指针变量通常缩写为 ptr 。

  1. 注意事项
  2. 在书写表达式类似 var p *type 时,切记在 * 号和指针名称间留有一个空格,因为 - var p*type
  3. 语法正确的,但是在更复杂的表达式中,它容易被误认为是一个乘法表达式!

注意:

符号 * 可以放在一个指针前,如 *intP ,那么它将得到这个指针指向地址上所存储的值;这被称为反引用
(或者内容或者间接引用)操作符;另一种说法是指针转移。
对于任何一个变量 var, 如下表达式都是正确的: var == *(&var) 。

现在,我们应当能理解 pointer.go 中的整个程序和他的输出:

示例 pointer.go:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var i1 =
  5. fmt.Printf("An integer: %d, its location in memory: %p\n", i1, &i1)
  6. var intP *int
  7. intP = &i1
  8. fmt.Printf("The value at memory location %p is %d\n", intP, *intP)
  9. }

pointer.go

    输出:

程序 string_pointer.go 为我们展示了指针对string的例子。
它展示了分配一个新的值给 *p 并且更改这个变量自己的值(这里是一个字符串)。

  示例  string_pointer.go

  1. package main
  2. import "fmt"
  3. func main() {
  4. s := "good bye"
  5. var p *string = &s
  6. *p = "ciao"
  7. fmt.Printf("Here is the pointer p: %p\n", p) // prints address
  8. fmt.Printf("Here is the string *p: %s\n", *p) // prints string
  9. fmt.Printf("Here is the string s: %s\n", s) // prints same string
  10. }

string_pointer.go

     输出:

通过对 *p 赋另一个值来更改“对象”,这样 s 也会随之更改 。

注意事项
你不能得到一个文字或常量的地址,例如

注意事项
你不能得到一个文字或常量的地址,例如

  1. const i =
  2. ptr := &i //error: cannot take the address of i
  3. ptr2 := & //error: cannot take the address of 10

所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。但是对于经常导
致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如: pointer+2 ,移动指针指向字符串
的字节数或数组的某个位置)是不被允许的。Go 语言中的指针保证了内存安全,更像是 Java、C# 和VB.NET 中的引用。
因此 c = *p++ 在 Go 语言的代码中是不合法的。

指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传
递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都
有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,
所以从它们被创建开始就具有相互独立的生命周期。

另一方面(虽然不太可能),由于一个指针导致的间接引用(一个进程执行了另一个地址),指针的过度
频繁使用也会导致性能下降。

指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数
情况这会使你的代码结构不清晰。

如我们所见,在大多数情况下 Go 语言可以使程序员轻松创建指针,并且隐藏间接引用,如:自动反向引用。
对一个空指针的反向引用是不合法的,并且会使程序崩溃:

  示例 testcrash.go:

  1. package main
  2. func main() {
  3. var p *int = nil
  4. *p =
  5. }//
  6. in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/>
  7. // runtime error: invalid memory address or nil pointer dereference

testcrash.go

golang(二)的更多相关文章

  1. 从源码(编译)安装golang 二

    h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...

  2. C/C++调用Golang 二

    C/C++调用Golang 二 <C/C++调用Golang 一>简单介绍了C/C++调用Golang的方法步骤,只涉及一个简单的函数调用.本文总结具体项目中的使用场景,将介绍三种较复杂的 ...

  3. 记一次坑爹的golang 二维map判断问题

    记一次坑爹的golang 二维map判断问题 2018年10月18日 23:16:21 yinnnnnnn 阅读数:32更多 个人分类: golang   版权声明:本文为博主原创文章,未经博主允许不 ...

  4. Golang 二维切片初始化

    package main import "fmt" func main() { // 方法0 row, column := 3, 4 var answer [][]int for ...

  5. golang 二维切片

    初始化: res := make([][length]int, length), 例如: res := make([][2]int, 10) fmt.Println(res) 输出: [[0 0] [ ...

  6. golang 二维平面求多重遮挡三角形总面积

    解决问题描述:二维平面有很多三角形错落,可能会相互叠加落在一起,也可能互相远离.目标求出这些三角形的总占地面积. 我最开始想的解决方案是用总面积-总重叠面积 = 总占地面积.后来实现起来发现当面临多次 ...

  7. golang二维码

    package main import ( "github.com/boombuler/barcode" "github.com/boombuler/barcode/qr ...

  8. Golang的交互模式进阶-读取用户的输入

    Golang的交互模式进阶-读取用户的输入 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 读写数据除了 fmt 和 os 包,我们还需要用到 bufio 包来处理缓冲的输入和输出. ...

  9. Golang之路

    目录 Golang之路 Golang之路 Golang(一) - 开篇必须吹牛逼 Golang(二) - 第一个go程序和基本语法 Golang(三) - 函数 Golang(四) - 流程控制 Go ...

随机推荐

  1. Linux(Contos7)下使用SSH远程安装MySQL 8.0.17 完整笔记

    1. 使用putty 配置远程服务器连接,登录服务器. 由于没有指定下载包 使用 yum install mysql-server  提示 未指定包,如: 2. 因为甲骨文的收购了Mysql并且对My ...

  2. kafka部署在云服务器(centOS 6.5),本地远程连接问题

    kafka简介 Apache Kafka发源于LinkedIn,于2011年成为Apache的孵化项目,随后于2012年成为Apache的主要项目之一.Kafka使用Scala和Java进行编写.Ap ...

  3. FPGA综合的约束

    近日发现,有些逻辑电路的综合时间约束和布局布线约束相差太大时,难以布通.此时,应该选择尽量接近的时钟约束.

  4. R = [obj for obj in recs[imagename] if obj['name'] == classname] KeyError: '007765'

    在用RFBNet做测试的时候,好几次总是遇到 R = [obj for obj in recs[imagename] if obj['name'] == classname]  KeyError: ' ...

  5. AngularJS实现地址栏取值

    有时候我们由如下需求 1.从a.html跳转到b.html 2.从a跳转时携带参数和值. 3.从b.html中取出传过来的参数值 在AngularJS的操作如下 在a.html中添加 <a hr ...

  6. 初始化错误——从一个简单的算例看UDF各个宏的调用顺序

    感谢西安交通大学en_phert的问题和尝试 Fluent版本:Fluent 19.0 Visual Studio版本:Visual Studio 2013 在UDF的宏的调用中大家常看见下图: 这个 ...

  7. asp.net core 托管到windows服务,并用iis做反向代理

    使用NSSM把.Net Core部署至 Windows 服务   为什么部署至Windows Services 在很多情况下,很少会把.Net Core项目部署至Windows服务中,特别是Asp.n ...

  8. java中过滤器(Filter)与拦截器(Interceptor )区别

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是设置字符集.控制权限.控制转向.做一些业务逻辑判断等.其工作 ...

  9. enable device: BAR 0 [mem 0x00000000-0x003fffff] not claimed

    /******************************************************************************* * enable device: BA ...

  10. Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization

    Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization 2019-10-10 10:50:19 Paper ...