-
Go 有25个关键字。30多个预声明的常量,类型和函数(可以重声明,但是有风险)。(见书第20页)
-
包级别的声明对包里的所有文件可见,大写字母开头表示它是导出的。
-
包名本身用小写字母组成
-
命名采用驼峰式
- 有4个主要的声明:变量(var),常量(const),类型(type),函数(func)
// 类型和表达式可以省略其中一个
var name type = expression
- Go中不存在未初始化变量,各种类型的0值:
类型 | 0值 |
---|---|
数字 | 0 |
布尔值 | false |
字符串 | "" |
接口和引用类型(slice,指针,map,通道,函数) | nil |
复合类型(数组,结构体) | 元素或成员的0值 |
- 忽略类型允许声明多个不同类型的变量:
var b, f, s = true, 2.3, "four"
- 包级别的变量初始化在 main 开始之前进行。函数级别的在函数执行期间进行。
-
:= 表示声明,= 表示赋值
-
在 局部 变量的声明和初始化中主要使用短声明
-
使用 var 声明有两种情况:
-
初始化表达式和类型不一致:
var f float64 = 100
-
初始值不重要时,后面才赋值:
var names []string var p Point
-
-
只有对可读性有帮助时才使用多个表达式初始化变量,例如 for 循环的初始化:
for i, j := 0, 0; //...
-
在多个左值的声明中,短变量声明至少声明一个新变量:
in, err := os.Open(infile) // out为新变量 out, err := os.Create(outfile)
-
只有在同一个词法块中变量已经存在的情况下,短声明行为才和赋值一样。外层的声明将被忽略。
-
指针可以比较,两个指针指向同一变量或者都是 nil 时才相等
-
函数返回局部变量的值的指针是安全的
var p = f() func f() *int { v := 1 return &v }
-
指针产生别名。复制其他引用类型也产生别名。
-
表达式 new(T) 做三件事:
- 创建一个未命名的 T 类型变量
- 初始化为 T 类型的零值
- 返回其地址 ( 类型为 *T )
func newInt() *int { return new(int) } // 等同于 func newInt() *int { var i int return &i }
-
如果两个变量的类型不携带任何信息且都是零值,它们就具有相同的地址。例如类型为 struct{} 或 [0]int
-
new 不是关键字,可以重定义
-
变量的声明周期是通过它是否可达确定的
-
变量的逃逸
var g *int func f() { var x int x = 1 g = &x // 变量x从f逃逸 }
-
合理控制变量的声明周期,提高垃圾回收效率
-
用赋值操作符(+=, *=) 避免重复变量本身
-
用++,--,递增或递减
-
可以交换变量的值
-
让赋值表达式变得紧凑
-
同时返回操作结果:
v, ok = mmap[key] v, ok = x.(T) v, ok = <-ch
-
函数调用隐式地将参数赋值给参数变量
-
return 语句隐式地将 return 操作数赋值给结果
-
可赋值性:左右值类型必须精准匹配
-
可比较性:两个值如果可以使用 == 或 != 进行比较,第一个操作数相对于第二个操作数必须是可赋值的
-
type 声明(通常在包级别)定义一个新的类型,和某个已有类型使用同样的底层类型
type name underlyingType
-
不同类型间可以相互转换的条件:
-
具有相同的底层类型
-
或指向相同底层类型变量的未命名指针类型
-
-
不同命名类型的值不能比较
-
命名类型可以与其底层类型相同类型的未命名类型比较
-
包用于支持模块化,封装,编译隔离和重用
-
包给声明提供独立的命名空间
-
包导出的标识符以大写字母开头
-
package 声明前紧挨着文档注释,对整个进行描述。一个包只有一个文件应包含文档注释。扩展文档注释通常放在 doc.go 中
-
包名是包导入路径的最后一段
-
导入未使用的包会编译报错
-
任何文件可以包含任意数量的 init 函数声明:
func init() { /* ... */ }
-
init 函数不能被调用。程序启动时,init 函数按照声明的顺序执行
-
包的初始化按照在程序中导入的顺序来进行,main 包最后初始化
-
作用域是编译时属性,声明周期是运行时属性
-
声明的词法块决定声明作用域的大小。不用的词法块可以包含同名的声明。内层声明将覆盖外层声明
-
内置类型,函数,常量对整个程序可见
-
包级别的声明对整个包可见
-
导入的包,可见性是文件级别的
-
for, if, switch 都会创建隐式的词法块。注意在其中声明变量的生命周期。
-
内层词法块中的声明可能屏蔽全局变量,避免使用 :=
var cwd strings func init() { cwd, err := os.Getwd() // 错误 } // 应该 func init() { var err error cwd, err = os.Getwd() }