1. 命名规范
Go中函数、变量、常量、类型、语句标签和包的名称遵循一个简单的规则:名称的开头是一个字母或者下划线,后面可以跟任意数量的字符、数字和下划线,区分大小写。
Go中有25个关键字,不能够作为名称
另外还有三十多个内置的预声明的常量、类型和函数
2. 声明
声明给一个程序实体命名,并且设定了其全部或者部分属性。Go语言主要有四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明。
2.1 var 变量
变量是创建一个具体类型的变量,然后给它附加一个名字,设置它的初始值。
【1】短变量声明:最少声明一个新变量,否则编译错误
【2】指针:变量存储值得地方。指针的值是一个变量的地址,一个指针指向值保存的位置。不是所有的值都有地址,但是所有的变量都有。使用指针可以无需知道变量名字的情况下,间接读取或者更新变量的值。每次使用变量的地址或者复制一个指针,我们就创建了新的别名或者方式来标记同一变量。函数可以返回局部变量的地址是安全的。
//*运算表示获取指针地址的值
//&取地址表示返回变量值得地址
【3】调用内置的new函数。表达式new(T)将创建一个T类型的匿名变量,初始化为T类型的零值,然后返回变量地址,返回的指针类型为*T 。
【4】变量的作用周期。一个变量的有效周期只取决于是否可达,因此一个循环迭代内部的局部变量的生命周期可能超出其局部作用域。同时,局部变量可能在函数返回之后依然存在。
2.2 type 类型
变量或表达式的类型定义了对应存储值的属性特征,例如数值在内存的存储大小(或者是元素的bit
个数),它们在内部是如何表达的,是否支持一些操作符,以及它们自己关联的方法集等。
在任何程序中都会存在一些变量有着相同的内部结构,但是却表示完全不同的概念。例如,一个int
类型的变量可以用来表示一个循环的迭代索引、或者一个时间戳、或者一个文件描述符、或者一个
月份;一个float64类型的变量可以用来表示每秒移动几米的速度、或者是不同温度单位下的温度;
一个字符串可以用来表示一个密码或者一个颜色的名称。
一个类型声明语句创建了一个新的类型名称,和现有类型具有相同的底层结构。新命名的类型提供
了一个方法,用来分隔不同概念的类型,这样即使它们底层类型相同也是不兼容的。
type 类型名字 底层类型
const 常量
常量表达式的值在编译期计算,而不是在运行期。每种常量的潜在类型都是基础类型:boolean、string或数字。
一个常量的声明语句定义了常量的名字,和变量的声明语法类似,常量的值不可修改,这样可以防止在运行期被意外或恶意的修改。例如,常量比变量更适合用于表达像π之类的数学常数,因为它们的值不会发生变化。
所有常量的运算都可以在编译期完成,这样可以减少运行时的工作,也方便其他编译优化。当操作数是常量时,一些运行时的错误也可以在编译时被发现,例如整数除零、字符串索引越界、任何导致无效浮点数的操作等。常量间的所有算术运算、逻辑运算和比较运算的结果也是常量,对常量的类型转换操作或以下函数调用都是返回常量结果:len、cap、real、imag、complex和unsafe.Sizeof。
常量声明可以使用iota常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然后在每一个有常量声明的行加一。
/*
位移操作 << : 向左移位 可以看做是 乘以2的几次方
位移操作 >> : 向右移位 可以看做是 除以2的几次方
and操作 & : 都为1 才是1
or 操作 | : 只要有一个是1 那么就是1
取反 ^ :有一个为1 则 就是1 两个1 或者两个0 全是 0
标志位操作 &^ : a &^ b = (a^b) & b 其实就是清除标
(将a中为1的位 如果b中相同位置也为1,则将a中该位置修改为0,a中其他位不变)
*/
func 函数(或者方法)
函数可以让我们将一个语句序列打包为一个单元,然后可以从程序中其它地方多次调用。函数的机制可以让我们将一个大的工作分解为小的任务,这样的小任务可以让不同程序员在不同时间、不同地方独立完成。一个函数同时对用户隐藏了其实现细节。由于这些因素,对于任何编程语言来说,函数都是一个至关重要的部分。
函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。
func name(parameter‐list) (result‐list) {
body
}
3. 包和文件
Go语言中的包和其他语言的库或模块的概念类似,目的都是为了支持模块化、封装、单独编译和代码重用。一个包的源代码保存在一个或多个以.go为文件后缀名的源文件中,通常一个包所在目录路径的后缀是包的导入路径。例如包导入路径xx/yy/zz对应的目录路径是
$GOPATH/src/xx/yy/zz。每个包都对应一个独立的名字空间。
包还可以让我们通过控制哪些名字是外部可见的来隐藏内部实现信息。在Go语言中,一个简单的规则是:如果一个名字是大写字母开头的,那么该名字是导出的(译注:因为汉字不区分大小写,因此汉字开头的名字是没有导出的)。
3.1 包注释
在每个源文件的包声明前紧跟着的注释是包注释。通常,包注释的第一句应该先是包的功能概要说明。一个包通常只有一个源文件有包注释(译注:如果有多个包注释,目前的文档工具会根据源文件名的先后顺序将它们链接为一个包注释)。如果包注释很大,通常会放到一个独立的doc.go文件中。
3.2 包导入和初始化
在Go语言程序中,每个包都是有一个全局唯一的导入路径。Go语言的规范并没有定义这些字符串的具体含义或包来自哪里,它们是由构建工具来解释的。当使用Go语言自带的go工具箱时,一个导入路径代表一个目录中的一个或多个Go源文件。
包的初始化首先是解决包级变量的依赖顺序,然后按照包级变量声明出现的顺序依次初始化,如果包中含有多个.go源文件,它们将按照发给编译器的顺序进行初始化,Go语言的构建工具首先会将.go文件根据文件名排序,然后依次调用编译器编译。
对于在包级别声明的变量,如果有初始化表达式则用表达式初始化,还有一些没有初始化表达式的,例如某些表格数据初始化并不是一个简单的赋值过程。在这种情况下,我们可以用一个特殊的init初始化函数来简化初始化工作。init初始化函数除了不能被调用或引用外,其他行为和普通函数类似。在每个文件中的init初始化函数,在程序开始执行时按照它们声明的顺序被自动调用。
4. 作用域
声明语句的作用域是指源代码中可以有效使用这个名字的范围。 不要将作用域和生命周期混为一谈。声明语句的作用域对应的是一个源代码的文本区域;它是一个编译时的属性。一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间区域内它可以被程序的其他部分引用;是一个运行时的概念。 语法块是由花括弧所包含的一系列语句,就像函数体或循环体花括弧对应的语法块那样。语法块内部声明的名字是无法被外部语法块访问的。语法块定了内部声明的名字的作用域范围。我们可以这样理解,语法块可以包含其他类似组批量声明等没有用花括弧包含的代码,我们称之为语法块。有一个语法块为整个源代码,称为全局语法块;然后是每个包的包语法块;每个for、if和switch语句的语法块;每个switch或select的分支也有独立的语法块;当然也包括显式书写的语法块(花括弧包含的语句)。 声明语句对应的词法域决定了作用域范围的大小。对于内置的类型、函数和常量,比如int、len和true等是在全局作用域的,因此可以在整个程序中直接使用。任何在在函数外部(也就是包级语法域)声明的名字可以在同一个包的任何源文件中访问的。