1.块
块为一对大括号括住的声明和语句。块 = "{" { 语句 ";" } "}" .
除显式源码块外,还有隐式块:
- 全域块 包含所有的Go源码文本。
- 每个包都有包含其所有Go源码文本的 包块。
- 每个文件都有包含其所有Go源码文本的 文件块。
- 每个
if
、for
和switch
语句都被视为处于其自身的隐式块中。 - 每个
switch
或select
语句中的子句其行为如同隐式块。
块可嵌套并会影响作用域。
2.标识符
标识符被用来命名程序实体,例如变量和类型。一个标识符由一个或多个字母和数字组成。 标识符的第一个字符必须是字母。
给定一个标识符集,若其中一个标识符不同于该集中的任一标识符,那么它就是唯一的。 若两个标识符拼写不同,或它们出现在不同的包中且未 导出,那么它们就是不同的。否则,它们就是相同的。
空白标识符
空白标识符 通过下划线字符 _ 表示, 它可像其它标识符一样用于声明,但该标识符不能传入一个新的绑定。
预声明标识符
在全局块中,以下标识符是隐式声明的:
类型: bool byte complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr 常量: true false iota 零值: nil 函数: append cap close complex copy delete imag len make new panic print println real recover
已导出标识符
标识符可被 导出 以允许从另一个包访问。同时符合以下条件即为已导出标识符:
其它所有标识符均为未导出的。
关键字
以下为保留关键字,不能用作标识符。
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
3.声明和作用域
声明可将非空白标识符"_"绑定到一个常量、类型、变量、函数或包。 在程序中,每个标识符都必须被声明。
作用域 即为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。
作用域说明:
- 预声明标识符的作用域为全域块。
- 在顶级(即在任何函数之外)声明的表示常量、类型、变量或函数(而非方法)的标识符其作用域为该包块。
- 已导入包的包名作用域为包含该导入声明的文件块。
- 表示方法接收器、函数形参或返回值变量的标识符,其作用域为该函数体。
- 在函数中声明为常量或变量的标识符,其作用域始于该函数中具体常量实现或变量实现ShortVarDecl表示短变量声明)的结尾,止于最内部包含块的结尾。
- 在函数中声明为类型的标识符,其作用域始于该函数中具体类型实现的标识符,止于最内部包含块的结尾。
注意:
- 同一标识符不能在同一块中声明两次,且在文件与包块中不能同时声明。
- 在块中声明的标识符可在其内部块中重新声明。 当其内部声明的标识符在作用域中时,即表示其实体在该内部声明中声明。
- 包子句(package xxx)并非声明;包名不会出现在任何作用域中。 其目的是为了识别该文件是否属于相同的包并为导入声明指定默认包名。
标签作用域:
标签通过标签语句声明(标识符:语句),并用于 break、continue 和 goto 语句.例如:
L: for i < n { switch i { case 5: break L } }
定义不会使用的标签是非法的。与其它标识符相反,标签并不限定作用域且与非标签标识符并不冲突。 标签的作用域为除任何嵌套函数体外其声明的函数体。
4.各种声明
常量声明
const Pi float64 = 3.14159265358979323846 const zero = 0.0 // 无类型化浮点常量 const ( size int64 = 1024 eof = -1 // 无类型化整数常量 ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 无类型化整数和字符串常量 const u, v float32 = 0, 3 // u = 0.0, v = 3.0
iota
iota可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1
const ( // iota重置为0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // 该常量未导出 )
在表达式列表中,每个 iota 的值都相同,因为它只在每个常量实现后增量。
const ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 bit1, mask1 // bit1 == 2, mask1 == 1 _, _ // skips iota == 2 bit3, mask3 // bit3 == 8, mask3 == 7 )
类型声明
声明类型不继承任何方法绑定到现存类型, 但接口类型或复合类型元素的方法集保持不变:
// Mutex为带有Lock和Unlock两个方法的数据类型. type Mutex struct { /* Mutex字段 */ } func (m *Mutex) Lock() { /* Lock实现*/ } func (m *Mutex) Unlock() { /* Unlock实现*/ } // NewMutex和Mutex拥有相同的组成,但它的方法集为空. type NewMutex Mutex // PtrMutex的基础类型的方法集保持不变. // 但PtrMutex的方法集为空. type PtrMutex *Mutex // *PrintableMutex的方法集包含方法 // Lock和Unlock绑定至其匿名字段Mutex. type PrintableMutex struct { Mutex } // MyBlock为与Block拥有相同方法集的接口类型. type MyBlock Block
类型声明可用来定义不同的布尔值、数字或字符串类型并对其附上方法:
type TimeZone int const ( EST TimeZone = -(5 + iota) CST MST PST ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT+%dh", tz) }
变量声明
变量声明将一个标识符绑定至一个创建的变量并赋予其类型和可选的初始值。
若给定一个表达式列表,则变量通过按顺序将该表达式赋予该变量(§赋值)来初始化;所有表达式必须用尽且所有变量根据它们初始化。
否则,每个变量初始化为其 零值。若该类型已存在,每个变量都赋予该类型。
否则,该类型根据该表达式列表赋值。
若该类型不存在且其对应表达式计算结果为无类型化常量, 则该声明变量的类型由其赋值描述。
实现限制:若在函数体内声明不会使用的变量,编译器可能将其判定为非法
var i int var U, V, W float64 var k = 0 var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // 映射检查;只与“found”有关
短变量声明
短变量声明只能出现在函数内部。在某些情况下,例如初始化 if、 for、或 switch 语句时,它们可用来声明局部临时变量
i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) r, w := os.Pipe(fd) // os.Pipe() 返回两个值 _, y, _ := coord(p) // coord() 返回三个值;只与和y同位的值相关
不同于常规变量声明,在至少有一个非空白变量时,短变量声明可在相同块中,对原先声明的变量以相同的类型重声明。 因此,重声明只能出现在多变量短声明中。 重声明不能生成新的变量;它只能赋予新的值给原来的变量。
field1, offset := nextField(str, 0) field2, offset := nextField(str, offset) // 重声明 offset 在同一个块中使用var 重复声明是非法的 a, a := 1, 2 // 非法:重复声明了 a,或者若 a 在别处声明,但此处没有新的变量
函数声明
函数声明可省略函数体。这样的标识符为Go外部实现的函数提供签名,例如汇编例程。
func min(x int, y int) int { if x < y { return x } return y } func flushICache(begin, end uintptr) // 外部实现
方法声明
方法为带 接收者 的函数。方法声明将标识符,即 方法名 绑定至方法。 它也将该接收者的 基础类型 关联至该方法。
接收者类型必须为形式 T 或 *T,其中 T 为类型名。
由 T 表示的类型称为接收者的 基础类型; 它不能为指针或接口类型且必须在同一包中声明为方法。
若该接收器的值并未在该方法体中引用,其标识符可在声明中省略。这同样适用于一般函数或方法的形参。
func (p *Point) Length() float64 { return math.Sqrt(p.x * p.x + p.y * p.y) } func (p *Point) Scale(factor float64) { p.x *= factor p.y *= factor } func (Point) Scale(factor float64) { .... }