go声明和初始化
go声明和初始化
当我们第一次看见变量和声明时,我们仅仅看见一些内置的类型,比如整型和字符串。现在我们将学习结构体,并且我们会深入学习包括指针的内容。
通过一种最简单的方式去创建一个结构体值类型:
goku := Saiyan{
Name: "Goku",
Power: 9000,
}
注意:上面的结构体中,结尾的逗号,
是不能省的。如果没有逗号,编译器会给出一个错误。你将喜欢上这种一致性要求,特别是如果你已经使用一种相反的语言或格式。
我们不需要给结构体设置任何值甚至任何字段。这2中方式都是有效的:
goku := Saiyan{}
// 或者
goku := Saiyan{Name: "Goku"}
goku.Power = 9000
这就像一个未赋值的变量一样,结构体的字段也会有一个0值。
另外,你也可以省略字段的名字,按字段的顺序进行声明(尽管为了简洁起见,你尽量在结构体只有少量字段时才使用这种方式):
goku := Saiyan{"Goku", 9000}
上面的例子主要是声明了一个变量goku
,并给它赋值。
尽管在大多数时候,我们不希望一个变量直接关联一个值,而是希望一个指针指向变量的值。指针是一个内存地址。通过指针可以找到这个变量实际的值。这是一种间接的取值。严格地说,这与存在一个房子并指向另外一个房子有一些区别。
为什么我们需要一个指针指向一个值,而不需要一个实际值。这主要是因为在go语言中,函数的参数传递都是按值传递,即传递的是一个拷贝。了解到这点,下面程序会打印什么?
func main() {
goku := Saiyan{"Goku", 9000}
Super(goku)
fmt.Println(goku.Power)
}
func Super(s Saiyan) {
s.Power += 10000
}
答案是9000,不是19000。为什么?因为Super
只是改变了goku
的一个拷贝,所以在Super
中的改变不会调用者中反应出来。如果你希望答案是19000,我们需要传递一个指向我们值的指针:
func main() {
goku := &Saiyan{"Goku", 9000}
Super(goku)
fmt.Println(goku.Power)
}
func Super(s *Saiyan) {
s.Power += 10000
}
我们改变了2个地方。首先是使用了&
操作符去获得我们值的地址(&
叫取地址符)。接下来,我们改变了Super
接受的参数类型。之前我们是传递一个Saiyan
的值类型,现在我们传递了一个地址类型*Saiyan
,这里的*X
表示一个指向类型X
的一个指针。显而易见,Saiyan
和*Saiyan
类型之间有一定的联系,但是它们是两种不同的类型。
需要指出的是,我们现在传递给Super
参数的仍然是goku
的值拷贝。只是现在goku
的值变成了一个地址。这个地址拷贝和源地址相同。可以认为它类似一个指向餐厅方向的拷贝,这就间接服务于我们。虽然是一个拷贝,但是和源地址一样,也指向同一个餐厅。
我们能证明这是一个拷贝,通过试着去改变它指向的地方(这可能不是你想做的):
func main() {
goku := &Saiyan{"Goku", 9000}
Super(goku)
fmt.Println(goku.Power)
}
func Super(s *Saiyan) {
s = &Saiyan{"Gohan", 1000}
}
上面的代码在此输出了9000。很多语言也有类似的行为,包括ruby、python、java和c#。go某种程度上和c#一样,只是让事实可见。
显而易见,复制一个指针变量的开销比复制一个复杂的结构体小。在一个64的系统上,指针的大小只有64位。如果我们的结构体有很多字段,创建一个结构体的拷贝会有很大的性能开销。指针的真正意义就是通过指针可以共享值。我们想通过Super
去改变goku
的拷贝或者改变共享的goku
值本身?
这里不是说你需要一直使用指针。本章的结尾,在我们学到更多关于结构体使用的内容之后。我们将重新审视值类型和指针类型的问题。
本文转自:http://codingdict.com/article/22523
go声明和初始化的更多相关文章
- Java 数组声明与初始化
引言 学习了好久的java,每次要写数组的声明和初始化代码,总是理不清.最近又碰到了一次这种情况.这次拿出<Thinking In Java>好好总结一翻. 数组声明 对于数组的声明其实都 ...
- 关于Javascript循环体变量声明与初始化的效率问题
针对循环体变量声明与初始化的效率问题,将执行的简单测试代码如下: function test(n) { console.time('Internally initialized'); for (var ...
- Java类对象数组声明和初始化
Java是纯面向对象语言.类是其重要构成单位. 然后,在实际编程中,我们会自己定义一些类,如Point <span style="font-size:14px;">pu ...
- C++二维数组讲解、二维数组的声明和初始化
我们知道,一维空间是一条线,数学中用一条数轴来表达:二维空间是一个平面,数学中用平面坐标系来表达.那么二维数组又是什么样的呢? 线与面 我们用一个下标来描述一维数组中的某个元素,就好像在用数描述一条线 ...
- java中static变量的声明和初始化
目录(?)[+] 问题1静态变量如何初始化 问题2JDK如何处理static块 问题3如何看待静态变量的声明 对初始问题的解答 在网上看到了下面的一段代码: public class Test ...
- c++中的结构体:声明 定义 初始化
什么是结构体? 之前的学习中我们知道了数组是一个容器,而且是存放固定大小数据的容器,而且存放的元素的数据类型必须要一致. 比如数据库中有这样的一条记录学号 性别 年龄 成绩 地址应该怎样存放 结构体: ...
- 【C++】const,static和static const类型成员变量声明及其初始化
1)const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间 void f1() { ; cout<<x<<endl; ...
- C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化
C++类有几种类型的数据成员:普通类型.常量(const).静态(static).静态常量(static const).这里分别探讨以下他们在C++11之前和之后的初始化方式. c++11之前版本的初 ...
- C++ static、const和static const类型成员变量声明以及初始化
C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. sta ...
随机推荐
- 关于Linux_监控系统资源/性能命令_vmstat
(系统资源查看命令-vmstat[监控系统资源命令]) command:vmstat [刷新延时 刷新次数] 分解解析: procs:进程信息字段: ...
- Python每日一题 006
题目 你有一个目录,装了很多照片,把它们的尺寸变成都不大于 iPhone5 分辨率的大小. 如果只是单纯的通过将图片缩放到iPhone5分辨率大小,显然最后呈现出来的效果会很糟糕.所以等比例缩放到长( ...
- ROM、PROM、EPROM、EEPROM、Flash ROM分别指什么?
ROM指的是“只读存储器”,即Read-Only Memory.这是一种线路最简单半导体电路,通过掩模工艺, 一次性制 造,其中的代码与数据将永久保存(除非坏掉),不能进行修改.这玩意一般在大批量生产 ...
- Branch policies on Azure Repos
https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies-overview?view=azure-devops B ...
- VPS性能测试:CPU内存,硬盘IO读写,带宽速度,UnixBench和压力测试
现在便宜的VPS主机越来越多了,一些美国的VPS主机甚至给出1美元一月的VPS,堪比虚拟主机还要便宜,巨大的价格优势吸引不少人购买和使用,而近些年来国内的主机商也开始意识到便宜的VPS对草根站长的诱惑 ...
- git的使用(本地版本库)
1. 创建版本库 1.1 创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录: 1.2通过git init命令把这个目录变成Git可以管理的仓库(git进入空目录的路径) $ git i ...
- Eureka 系列(07)服务注册与主动下线
Eureka 系列(07)服务注册与主动下线 [TOC] Spring Cloud 系列目录 - Eureka 篇 在上一篇 Eureka 系列(05)消息广播 中对 Eureka 消息广播的源码进行 ...
- leetcode.位运算.136只出现一次的元素-Java
1. 具体题目 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明:你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1 ...
- proc伪文件系统 - 加载一个进程
内核模块的编译方法及注意事项 Ubuntu内核(2.6.32) 2.6内核中,模块的编译需要配置过的内核源码:编译.链接后生成的内核模块后缀为.ko:编译过程首先会到内核源码目录下读取顶层的Makef ...
- 使用IO流将数据库中数据生成一个文件,结果使用Notepad++打开部分数据结尾出现NUL
场景描述: 项目中通过java代码中从数据库中查询一系列数据,对数据做相应处理,然后通过字符流将数据写如一个新生成的文件中,将该项目部署在linux服务器上,最后生成的文件拿到本地使用notepad+ ...