go声明和初始化

当我们第一次看见变量和声明时,我们仅仅看见一些内置的类型,比如整型和字符串。现在我们将学习结构体,并且我们会深入学习包括指针的内容。

通过一种最简单的方式去创建一个结构体值类型:

  1. goku := Saiyan{
  2. Name: "Goku",
  3. Power: 9000,
  4. }

注意:上面的结构体中,结尾的逗号,是不能省的。如果没有逗号,编译器会给出一个错误。你将喜欢上这种一致性要求,特别是如果你已经使用一种相反的语言或格式。

我们不需要给结构体设置任何值甚至任何字段。这2中方式都是有效的:

  1. goku := Saiyan{}
  2. // 或者
  3. goku := Saiyan{Name: "Goku"}
  4. goku.Power = 9000

这就像一个未赋值的变量一样,结构体的字段也会有一个0值。

另外,你也可以省略字段的名字,按字段的顺序进行声明(尽管为了简洁起见,你尽量在结构体只有少量字段时才使用这种方式):

goku := Saiyan{"Goku", 9000}

上面的例子主要是声明了一个变量goku,并给它赋值。

尽管在大多数时候,我们不希望一个变量直接关联一个值,而是希望一个指针指向变量的值。指针是一个内存地址。通过指针可以找到这个变量实际的值。这是一种间接的取值。严格地说,这与存在一个房子并指向另外一个房子有一些区别。

为什么我们需要一个指针指向一个值,而不需要一个实际值。这主要是因为在go语言中,函数的参数传递都是按值传递,即传递的是一个拷贝。了解到这点,下面程序会打印什么?

  1. func main() {
  2. goku := Saiyan{"Goku", 9000}
  3. Super(goku)
  4. fmt.Println(goku.Power)
  5. }
  6. func Super(s Saiyan) {
  7. s.Power += 10000
  8. }

答案是9000,不是19000。为什么?因为Super只是改变了goku的一个拷贝,所以在Super中的改变不会调用者中反应出来。如果你希望答案是19000,我们需要传递一个指向我们值的指针:

  1. func main() {
  2. goku := &Saiyan{"Goku", 9000}
  3. Super(goku)
  4. fmt.Println(goku.Power)
  5. }
  6. func Super(s *Saiyan) {
  7. s.Power += 10000
  8. }

我们改变了2个地方。首先是使用了&操作符去获得我们值的地址(&叫取地址符)。接下来,我们改变了Super接受的参数类型。之前我们是传递一个Saiyan的值类型,现在我们传递了一个地址类型*Saiyan,这里的*X表示一个指向类型X的一个指针。显而易见,Saiyan*Saiyan类型之间有一定的联系,但是它们是两种不同的类型。

需要指出的是,我们现在传递给Super参数的仍然是goku的值拷贝。只是现在goku的值变成了一个地址。这个地址拷贝和源地址相同。可以认为它类似一个指向餐厅方向的拷贝,这就间接服务于我们。虽然是一个拷贝,但是和源地址一样,也指向同一个餐厅。

我们能证明这是一个拷贝,通过试着去改变它指向的地方(这可能不是你想做的):

  1. func main() {
  2. goku := &Saiyan{"Goku", 9000}
  3. Super(goku)
  4. fmt.Println(goku.Power)
  5. }
  6. func Super(s *Saiyan) {
  7. s = &Saiyan{"Gohan", 1000}
  8. }

上面的代码在此输出了9000。很多语言也有类似的行为,包括ruby、python、java和c#。go某种程度上和c#一样,只是让事实可见。

显而易见,复制一个指针变量的开销比复制一个复杂的结构体小。在一个64的系统上,指针的大小只有64位。如果我们的结构体有很多字段,创建一个结构体的拷贝会有很大的性能开销。指针的真正意义就是通过指针可以共享值。我们想通过Super去改变goku的拷贝或者改变共享的goku值本身?

这里不是说你需要一直使用指针。本章的结尾,在我们学到更多关于结构体使用的内容之后。我们将重新审视值类型和指针类型的问题。

本文转自:http://codingdict.com/article/22523

go声明和初始化的更多相关文章

  1. Java 数组声明与初始化

    引言 学习了好久的java,每次要写数组的声明和初始化代码,总是理不清.最近又碰到了一次这种情况.这次拿出<Thinking In Java>好好总结一翻. 数组声明 对于数组的声明其实都 ...

  2. 关于Javascript循环体变量声明与初始化的效率问题

    针对循环体变量声明与初始化的效率问题,将执行的简单测试代码如下: function test(n) { console.time('Internally initialized'); for (var ...

  3. Java类对象数组声明和初始化

    Java是纯面向对象语言.类是其重要构成单位. 然后,在实际编程中,我们会自己定义一些类,如Point <span style="font-size:14px;">pu ...

  4. C++二维数组讲解、二维数组的声明和初始化

    我们知道,一维空间是一条线,数学中用一条数轴来表达:二维空间是一个平面,数学中用平面坐标系来表达.那么二维数组又是什么样的呢? 线与面 我们用一个下标来描述一维数组中的某个元素,就好像在用数描述一条线 ...

  5. java中static变量的声明和初始化

     目录(?)[+] 问题1静态变量如何初始化 问题2JDK如何处理static块 问题3如何看待静态变量的声明 对初始问题的解答 在网上看到了下面的一段代码: public class Test  ...

  6. c++中的结构体:声明 定义 初始化

    什么是结构体? 之前的学习中我们知道了数组是一个容器,而且是存放固定大小数据的容器,而且存放的元素的数据类型必须要一致. 比如数据库中有这样的一条记录学号 性别 年龄 成绩 地址应该怎样存放 结构体: ...

  7. 【C++】const,static和static const类型成员变量声明及其初始化

    1)const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间 void f1() { ; cout<<x<<endl; ...

  8. C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化

    C++类有几种类型的数据成员:普通类型.常量(const).静态(static).静态常量(static const).这里分别探讨以下他们在C++11之前和之后的初始化方式. c++11之前版本的初 ...

  9. C++ static、const和static const类型成员变量声明以及初始化

    C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. sta ...

随机推荐

  1. Spring开发总结

    自动装载配置开启: spring.factories内容: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.b ...

  2. 【原理】scan

    SCAN 命令的保证(guarantees) 同一个元素可能会被返回多次. 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上. 如果一个元 ...

  3. UNP学习 多播

    一.概述 单播地址标识单个接口,广播地址标识子网上的所有接口,多播地址标识一组接口. 单播和广播是编址方案的两个极端,多播的目的就在于提供一种折衷的方案. 二.多播地址 我们必须区分IPv4多播地址和 ...

  4. JMeter 阶梯式加压测试插件 Concurrency Thread Group

    jmeter阶梯式加压测试:JMeter 阶梯式加压测试插件 Stepping Thread Group 由于Stepping Thread Group插件相对来说过于老旧,已不被官方所推荐. 所以这 ...

  5. 浏览器 url 编码

    1.问题的由来 : http://www.ruanyifeng.com/blog/2010/02/url_encoding.html 2.网络标准RFC 1738做了硬性规定: 只有字母和数字[0-9 ...

  6. 【c#技术】一篇文章搞掂:水晶报表

    更新数据源 应该先从[数据库]——[数据库专家]——[刷新]——[数据库]——[验证数据库] 必须先刷新,不然验证数据库无效 XP下,打开水晶报表提示无法创建目录或文件,删除临时目录Temp中文件即可 ...

  7. ThinkPHP5使用jwt进行会话验证

    以往,没有做过前后端分离的项目之前,都是服务器渲染的模板,然后用cookie和session进行账号的权限验证或者是登录状态的管理.后来接触了vue和小程序之后,在进行前后端分离的时候,就会遇到权限验 ...

  8. iOS之CAReplicatorLayer属性简介和使用

    1.CAReplicatorLayer简介 CAReplicatorLayer用于对图层进行复制,包括图层的动画也能复制!可以看着将某一段事务进行重复! #import <QuartzCore/ ...

  9. 大数据学习之BigData常用算法和数据结构

    大数据学习之BigData常用算法和数据结构 1.Bloom Filter     由一个很长的二进制向量和一系列hash函数组成     优点:可以减少IO操作,省空间     缺点:不支持删除,有 ...

  10. javascript函数调用的几种方式

    ​ function fn() { console.log(this.name); return "fn函数的返回值"; } /*1.方法调用*/ //方法调用,this指向win ...