第二章 程序结构

2.1 命名

在GO语言中,所有的变量名、函数、常量、类型、语句标号、包名都遵循一个原则:

名字必须以字母或者下划线开头,后面紧跟任意数量的字母数字下划线。区分大小写。

在GO语言中包含25个关键字:

| break   | default   | func   | interface | select |
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const |fallthrough| if | range | type |
| continue| for | import | return | var |

注意:GO语言中没有while关键字…

在Go语言中大约有30多个预定义的名字,主要为内建的常量、变量以及函数。

内建常量:true false iota nil

内建类型:int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64
float32 float64 complex128 complex64
bool byte rune string error 内建函数:make len cap new append copy close delete
complex real imag
panic recover

一般情况情况下:名字的首字母大小写决定了名字在包外的可见性。如果包外可见,则使用以大写字母开头,如Println()
Go语言命名遵循"驼峰式"原则,即变量有多个字母混合组成时,首字母大写的方式,不是采用下划线分割的方式。

2.2 声明

声明语句定义了程序各种实体对象,以及他们的部分或者全部属性。Go语言中主要包含4种类型的声明语句:var、const、type、func,他们分别对应变量、常量、类型、函数实体对象的声明。

一个Go语言编写的程序对应一个或多个以.go为文件后缀名的源文件中。

  • 每个源文件以包的声明语句开始,说明该源文件是属于哪个包。
  • 包声明语句之后是import语句导入依赖的其它包,
  • 然后是包一级的类型、变量、常量、函数的声明语句,包一级的各种类型的声明语句的顺序无关紧要。

例如,下面的例子中声明了一个常量、一个函数和两个变量:

package main

import "fmt"

/*水的沸点*/
const boilingF = 212.0 func main() {
var f = boilingF
var c = (f - 32) * 5 / 9 fmt.Printf("boiling point = %g°F or %g°C", f, c)
}

结果如下:

boiling point = 212°F or 100°C

函数和变量的使用如下:

package main

import "fmt"

func main() {
const freezingF, boilingF = 32.0, 212.0 fmt.Printf("%g°F = %g°C\n", freezingF, ftoc(freezingF))
fmt.Printf("%g°F = %g°C\n", boilingF, ftoc(boilingF)) } func ftoc(f float64) float64 {
return (f - 32) * 5 / 9
}

运行结果:

32°F = 0°C
212°F = 100°C

2.3 变量

var声明语句可以创建一个特定类型的变量,然后给变量附加一个名字,而且设置变量的初始值。变量的声明语法如下:

var 变量名 类型 = 表达式

其中"类型"或者"=表达式"可以省略其中一个。

  • 如果省略"类型",则根据初始值表达式推导出变量的类型
  • 如果省略"=表达式", 则将其初始化为该类型的0值

在Go语言中,零值初始化机制可以保证每一个声明的变量都有一个很好的初始值,不存在未初始化的变量。

包级别声明的变量会在main入口函数执行前完成初始化,局部变量将会在声明语句被执行到的时候在完成初始化。
一组变量也可以通过条用一个函数,有函数的多个返回值来完成初始化。

    var f, err = os.Open("/usr/local/avi/xxoo.avi")/*os.Open return a file and an error*/

2.3.1 简短声明

在函数内部,有一个简短变量声明方式可用于声明和初始化局部变量。它以"名字:=表达式"形式声明变量。变量的类型根据表达式来自动推导。

简短声明因为简洁和灵活的特点,被广泛用于大部分局部变量的声明和初始化。

var形式的声明语句往往用于需要显式指定变量类型的地方,或者因为变量稍后重新复制而初始值无关紧要的地方。

i := 100
var boiling float64 = 100.0
var names []string
var err error
var p Point

与var形式声明变量语句一样,简短声明也可以用来声明和初始化一组变量:
i, j := 1, 2

简短声明有一个需要注意的地方:

变量 := 表达式

  • 简短声明左边的变量可能不是全部刚刚声明的,允许使用先前已经声明的变量,如果已经声明了,那么这里只是赋值操作。
  • 简短声明中必须至少要声明一个新的变量,否则无法编译通过。
  • 简短声明语句只有对已经存在的同级词法域声明过的变量才和赋值操作等价。
    fp, err := os.Open(xxx.avi)

    /* xxoo blabla*/

    newFp, err := os.Create(ooo.avi)

上面使用简短声明的方式没有语法错误,但是下面的简短声明则无法编译通过:

    fp, err := os.Open(xxx.avi)

    /* xxoo blabla*/

    fp, err := os.Create(ooo.avi)

2.3.2 指针

基本原则同C语言。

    x := 1
p := &x
  • 任何类型的指针的零值都是nil
  • 在Go语言中,返回函数中的局部变量的地址也是安全的…

2.3.3 new函数

另一个创建变量的方法是调用用内建的new函数。
表达式new(T)将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址,返回的指针类型为*T。

    p := new(int)
fmt.Println(*p)
*p = 2
fmt.Println(*p)

运行结果:

    0
2

用new创建变量和普通变量声明语句方式创建变量没有什么区别,除了不需要声明一个临时变量的名字外,我们还可以在表达式中使用new(T)。
使用new函数来声明变量比较少见。

在Go允许存在大小为0的数据,结构体…
new 是Go语言内置的变量名。

2.3.4 变量的生命周期

Go语言存在垃圾回收机制。
Go语言的自动垃圾收集器对编写正确的代码是一个巨大的帮助,但也并不是说你完全不用考虑内存了。
你虽然不需要显式地分配和释放内存,但是要编写高效的程序你依然需要了解变量的生命周期。
例如,如果将指向短生命周期对象的指针保存到具有长生命周期的对象中,特别是保存到全局变量时,会阻止对短生命周期对象的垃圾回收(局部变量逃逸)。

  • 局部变量逃逸
    var global *int

    func f(){
var x int
x = 1
global = &x
}

在Go语言中,上述代码是合法的,但是由于x是函数内的局部变量,却将其保存到全局变量中,导致声明周期延长。Go的术语称之为:“局部变量x从函数f中逃逸了”

2.4 赋值

赋值操作比较简单,直接举几个例子来说明:

    x = 1
*p = true
person.name = "Toney"
count[x] = count[x] * scale
count[x] *= scale

赋值变量支持递增(++)和递减(--)语句。

自增和自减是语句,不是表达式,因此x = i++是不合法的。

    v := 1
v++ //合法
v-- //合法

2.4.1 元组赋值

元组赋值是同时对多个变量进行赋值的操作。
在赋值之前,赋值语句右边的所有的表达式会首先计算求值,然后在同一更新右边变量的值。

例如交换两个数据:

/*直接交换两个变量的值*/
x,y = y,x
a[i],a[j] = a[j],a[i] /*多个变量进行赋值*/
i,j,k = 1,2,3
f, err = os.Open("golang.txt") v, ok = m[key] //查找哈希MAP
v, ok = x.(T) //类型断言
v, ok = <-ch //接收通道数据

如果对于某个返回值不感兴趣,则可以使用’_'来代替,表示不关心此返回值:

    _, ok = m[key]           //返回2个值
_, ok = mm.[""], false //返回1个值
_ = mm[""] //返回1个值

2.4.2 可赋值性

赋值语句是显式的赋值形式

    medals := []string{"gold", "silver","water","soil"}

也可以单独每一个元素进行赋值:

    medals[0] = "gold"
medals[1] = "silver"
medals[2] = "water"
medals[3] = "soil"

无论是显式赋值还是隐式赋值,等号两边的类型必须相同。

2.5 类型

变量或表达式的类型定义了对应存储值的属性特征。

格式如下:

type 类型名字 底层类型

  • 类型声明语句一般出现在包一级,如果新创建的类型名字首字符大写,则在外部包也可以使用。
  • 两个拥有不同类型的值无法直接进行比较

2.6 包和文件

  • Go语言中的包和其他语言的库或模块的概念类似,目的都是为了支持模块化、封装、单独编译和代码重用
  • 每个包都对应一个独立的名字空间。
  • 包还可以让我们通过控制哪些名字是外部可见的来隐藏内部实现信息。
  • 在Go语言中,一个简单的规则是:如果一个名字是大写字母开头的,那么该名字是导出的
  • 注:由于汉字不区分大小写,因此无法导出。

2.7 作用域

  • 一个声明语句将程序中的实体和一个名字关联,比如一个函数或一个变量。
  • 声明语句的作用域是指源代码中可以有效使用这个名字的范围。

作用域和生命周期是两个不同的概念:

  • 作用域对应源代码的文本区域,是一个编译时的属性
  • 变量的生存周期是指运行时变量存在的有效时间段,在此时间区域内,可以被其他部分引用。

注意事项:

  • Go中内部声明会屏蔽同名的外部声明,因此需要特别注意简短声明方式

《Go语言圣经》阅读笔记:第二章程序结构的更多相关文章

  1. 深入理解 C 指针阅读笔记 -- 第二章

    Chapter2.h #ifndef __CHAPTER_2_ #define __CHAPTER_2_ /*<深入理解C指针>学习笔记 -- 第二章*/ /* 内存泄露的两种形式 1.忘 ...

  2. go 圣经阅读笔记之-入门

    go 圣经 这本书英文名为 <The Go Programming Language> 1. 简单hello world示例 helloworld.go package main impo ...

  3. 《图解HTTP》阅读笔记--第二章 简单的HTTP协议--第三章 HTTP报文信息

     第二章.简单的HTTP协议HTTP协议:HTTP协议用于客户端(请求资源的一端)和服务器端(响应回复提供资源的一端)的通信,是一种无状态协议HTTP1.1默认TCP持久连接,管线化发送(并行发送多个 ...

  4. 《ProgrammingHive》阅读笔记-第二章

    书本第二章的一些知识点,在cloudera-quickstart-vm-5.8.0-0上进行操作. 配置文件 配置在/etc/hive/conf/hive-site.xml文件里面,采用mysql作为 ...

  5. 《时间序列分析及应用:R语言》读书笔记--第二章 基本概念

    本章介绍时间序列中的基本概念.特别地,介绍随机过程.均值.方差.协方差函数.平稳过程和自相关函数等概念. 2.1时间序列与随机过程 关于随机过程的定义,本科上过相关课程,用的是<应用随机过程&g ...

  6. 《Interest Rate Risk Modeling》阅读笔记——第二章:债券价格、久期与凸性

    目录 第二章:债券价格.久期与凸性 思维导图 瞬时回报率-收益率的例子 第二章:债券价格.久期与凸性 思维导图 瞬时回报率-收益率的例子

  7. Redis实战阅读笔记——第二章

    在性能的要求下,如何获取重构之前的构件

  8. <C++Primer>第四版 阅读笔记 第二部分 “容器和算法”

    泛型算法中,所谓"泛型(generic)"指的是两个方面:这些算法可作用于各种不同的容器类型,而这些容器又可以容纳多种不同类型的元素. 第九章 顺序容器 顺序容器的元素排列次序与元 ...

  9. Redis实战阅读笔记——第二章(redis重构web)

    在性能的要求下,如何用redis重构已有的已有的部分,其实整个例子背后的思路挺好的.在应用缓存的过程中,还有一指标个需要考虑,读写比.

随机推荐

  1. 记录21.07.24 —— Vue的组件与路由

    VUE组件 作用:复用性 创建组件的三种方式 第一种:使用extends搭配component方法 第二种:直接使用component方法 只有用vue声明且命名的才称之为创建组件 注意:templa ...

  2. 浅谈vue响应式原理及发布订阅模式和观察者模式

    一.Vue响应式原理 首先要了解几个概念: 数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率. 双向绑定:数据改变,视图 ...

  3. 2010 NOIP提高组题解

    机器翻译 用队列模拟题意即可 #include<cstdio> #include<iostream> #include<cstring> using namespa ...

  4. Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  5. C++ 结构体案例2 升序打印数组中的元素

    1 //结构体案例 2 2 #include<iostream> 3 #include<string> 4 #include<ctime> 5 using name ...

  6. Lateral Movement

    简介 这次去宁夏护网,发现我有的朋友连最基本的横向渗透有些都不晓得,他们问我 我也表达不清楚...,就想着写篇文章总结下吧 (慢慢更..) 可以发我邮箱讨论:muxue@protonmail.com ...

  7. Notepad++的NppFTP插件连接linux操作系统

    Notepad++的NppFTP插件连接linux操作系统 下载地址:https://notepad-plus-plus.org/downloads/v8.1.2/ 1.安装Npp_FTP插件 两种方 ...

  8. Blazor 模板化组件开发指南

    翻译自 Waqas Anwar 2021年4月15日的文章 <A Developer's Guide To Blazor Templated Components> [1] 在我之前的一篇 ...

  9. 慕慕生鲜上线&&腾讯云服务器配置准备

    1.购买服务器并配置环境 1.1 购买 618购买了腾讯云服务器三年最低配置(1核2G 1Mbps 50G云盘),一时激动忘记了购买前领优惠券,痛失25元. 1.2 环境配置 系统是 CentOS L ...

  10. Java基础技术基础面试【笔记】

    Java基础技术基础面试[笔记] String.StringBuilder以及StringBuffer三者之间的区别? 三者的区别可以从可变性,线程安全性,性能这三个部分进行说明 可变性 从可变性来说 ...