变量
-
为了方便操作内存特定位置的数据,我们用一个特定的名字与位于特定位置的内存块绑定在一起,这个名字被称为变量。变量所绑定的内存区域是要有一个明确的边界。
-
变量赋值可以进⾏⾃动类型推断
-
在一个赋值语句中可以对多个变量进⾏同时赋值
**func Test_fib(t *testing.T) { // var a int = 1 // var b int = 2 // var ( // a int = 1 // b int = 2 // ) var ( a = 1 b = 2 ) // a := 1 // b := 2 fmt.Print(a) for i := 0; i < 5; i++ { fmt.Print(" ", b) temp := a a = b b = temp + a } }** -
动态语言(比如 Python、Ruby 等)的解释器可以在运行时通过对变量赋值的分析,自动确定变量的边界。并且在动态语言中,一个变量可以在运行时被赋予大小不同的边界。
-
Go 是静态编程语言,使用变量之前需要先进行变量声明,告诉编译器该变量可以操作的内存的边界信息。
-
没有显式为变量赋予初值,Go 编译器会为变量赋予这个类型的零值。
-
Go 语言的变量可以分为两类:一类称为包级变量 (package varible),也就是在包级别可见的变量。如果是导出变量(大写字母开头),那么这个包级变量也可以被视为全局变量;另一类则是局部变量 (local varible),也就是 Go 函数或方法体内声明的变量,仅在函数或方法体内可见。而我们声明的所有变量都逃不开这两种。
-
包级变量只能使用带有 var 关键字的变量声明形式,不能使用短变量声明形式,但在形式细节上可以有一定灵活度。
-
这里我称这种方式为“声明聚类”,声明聚类可以提升代码可读性。
-
就近原则。也就是说我们尽可能在靠近第一次使用变量的位置声明这个变量。就近原则实际上也是对变量的作用域最小化的一种实现手段。
-
变量遮蔽是 Go 开发人员在日常开发工作中最容易犯的编码错误之一。一个变量的作用域起始于其声明所在的代码块,并且可以一直扩展到嵌入到该代码块中的所有内层代码块,而正是这样的作用域规则,成为了滋生“变量遮蔽问题”的土壤。
-
一个标识符的作用域就是指这个标识符在被声明后可以被有效使用的源码区域。作用域是一个编译期的概念。
常量
-
所有常量的求值计算都是在编译期完成的,而不是在运行期,这样可以减少运行时的工作,也方便编译器进行编译优化。另外,当操作数是常量表达式时,一些运行时的错误也可以在编译时被发现,例如整数除零、字符串索引越界等。
-
Go 语言在常量方面的创新包括下面这几点:
- 支持无类型常量;
- 支持隐式自动转型:对于无类型常量参与的表达式求值,Go 编译器会根据上下文中的类型信息,把无类型常量自动转换为相应的类型后,再参与求值计算,这一转型动作是隐式进行的。
- 可用于实现枚举。
-
使得 Go 常量是类型安全的,而且对编译器优化友好。
-
即便两个类型拥有着相同的底层类型,但它们仍然是不同的数据类型,不可以被相互比较或混在一个表达式中进行运算。
-
Go 的 const 语法提供了“隐式重复前一个非空表达式”的机制
-
iota 是 Go 语言的一个预定义标识符,它表示的是 const 声明块(包括单行声明)中,每个常量所处位置在块中的偏移值(从零开始)
-
位于同一行的 iota 即便出现多次,多个 iota 的值也是一样的
-
常量赋值
const ( Mon = iota + 1 Tues Wed ) func Test_const(t *testing.T) { fmt.Println(Mon, Tues, Wed) }const ( Readable = 1 << iota Writable Executable ) func Test_const(t *testing.T) { fmt.Println(Readable, Writable, Executable) }
运算符
-
Go 语⾔没有前置的 ++,- -,(++a)
-
用 == ⽐较数组:
-
相同维数且含有相同个数元素的数组才可以⽐较,
invalid operation: a == c (mismatched types [4]int and [5]int) -
每个元素都相同的才相等
func Test_op(t *testing.T) { a := [...]int{1, 2, 3, 4} b := [...]int{1, 2, 4, 5} d := [...]int{1, 2, 3, 4} t.Log(a == b, a == d) // false true }
-
-
逻辑运算符