golang的关键字
变量
var声明创建一个具体类型的变量,
- var name type = expression
Go是一种静态类型的语言,但是它仍然提供了一种在声明变量的同时省略数据类型声明的功能,类型和表达式可以省略一个,但是不能都省略;也就是golang支持类型推断
- var s string var b, f, s = true, 2, 3;
短变量声明
Golang中有两种创建变量的方法,如下所示:
-
使用var关键字
-
使用短变量声明运算符(:=)
使用短变量声明运算符的语法:
variable_name := 表达式 或 值 必须在声明后立即初始化变量,无需提及变量的类型, 右侧的表达式或值用于评估变量的类
声明仅具有块级作用域的局部变量
因其短小灵活,所以在局部变量的声明以及初始化中用的较多
:= 表示声明 而 = 表示赋值
只有在同一个词法语块中已经存在变量的情况下,短变量的行为才和赋值操作一样
go lang 中指针和clang 指针差不多
-
指针的声明和初始化可以在一行中完成。
var s *int = &a
*运算符 也称为解引用运算符,用于声明指针变量并访问存储在地址中的值。
&运算符 称为地址运算符,用于返回变量的地址或将变量的地址访问指针
new 函数
new是内建函数,函数原型为
func new(Type) *Type
The new build-in function allocates memory(仅仅分配空间). The first argument is a type, not a value, and the value returned is a pointer to a newly allocated zero value of that type.内置函数 new 分配空间。传递给new 函数的是一个类型,不是一个值。返回值是 指向这个新分配的零值的指针。
多重赋值:
允许同时更新多个变量的值。在赋值之前,赋值语句右边的所有表达式将会先进行求值,然后再统一更新左边对应变量的值。
有些表达式会产生多个值,比如调用一个有多个返回值的函数。当这样一个函数调用出现在元组赋值右边的表达式中时(译注:右边不能再有其它表达式),左边变量的数目必须和右边一致
作用域:
声明语句的作用域对应的是一个源代码的文本区域;它是一个编译时的属性。一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间区域内它可以被程序的其他部分引用;是一个运行时的概念。
基本数据:



字符串
unicode是信源编码,对字符集数字化;所有的字符和码位(数字)建立了对应关系
utf8是信道编码,为更好的存储和传输。
常量
常量是一种表达式,其保证在编译的时候计算出表达式的值,每种常量的潜在类型都是基础类型:boolean、string或数字。
常量间的所有算术运算、逻辑运算和比较运算的结果也是常量,对常量的类型转换操作或以下函数调用都是返回常量结果:len、cap、real、imag、complex和unsafe.Sizeof
如果是批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式写法,对应的常量类型也一样的。例如:
const ( a = 1 b c = 2 d ) fmt.Println(a, b, c, d) // "1 1 2 2"
常量声明可以使用iota常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然后在每一个有常量声明的行加一
下面是来自time包的例子,它首先定义了一个Weekday命名类型,然后为一周的每天定义了一个常量,从周日0开始。在其它编程语言中,这种类型一般被称为枚举类型。
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
周日将对应0,周一为1,如此等等。
数组
在数组字面值中,如果在数组的长度位置出现的是“...”省略号,则表示数组的长度是根据初始化值的个数来计算。因此,上面q数组的定义可以简化为
q := [...]int{1, 2, 3}
fmt.Printf("%T\n", q) // "[3]int"
for 和 range
除了for Go 语言引入了另一个关键字 range 帮助我们快速遍历数组、切片、哈希表以及 Channel 等集合类型
- 初始化循环的
Ninit; - 循环的继续条件
Left; - 循环体结束时执行的
Right; - 循环体
NBody:
for Ninit; Left; Right { NBody }
hash := map[string]int{ "1": 1, "2": 2, "3": 3, } for k, v := range hash { println(k, v) }
分析遍历数组和切片清空元素的情况;
分析使用 for range a {} 遍历数组和切片,不关心索引和数据的情况;
分析使用 for i := range a {} 遍历数组和切片,只关心索引的情况;
分析使用 for i, elem := range a {} 遍历数组和切片,关心索引和数据的情况;
SELECT:
Go 语言中的 select 也能够让 Goroutine 同时等待多个 Channel 可读或者可写,在多个文件或者 Channel状态改变之前,select 会一直阻塞当前线程或者 Goroutine。
select 是与 switch 相似的控制结构,与 switch 不同的是,select 中虽然也有多个 case,但是这些 case 中的表达式必须都是 Channel 的收发操作
C 语言的 select 系统调用可以同时监听多个文件描述符的可读或者可写的状态,Go 语言中的 select 也能够让 Goroutine 同时等待多个 Channel 可读或者可写,在多个文件或者 Channel状态改变之前,select 会一直阻塞当前线程或者 Goroutine
select 是与 switch 相似的控制结构,与 switch 不同的是,select 中虽然也有多个 case,但是这些 case 中的表达式必须都是 Channel 的收发操作
当我们在 Go 语言中使用 select 控制结构时,会遇到两个现象:
select能在 Channel 上进行非阻塞的收发操作;select在遇到多个 Channel 同时响应时,会随机执行一种情况;
在通常情况下,select 语句会阻塞当前 Goroutine 并等待多个 Channel 中的一个达到可以收发的状态。但是如果 select 控制结构中包含 default 语句,那么这个 select 语句在执行时会遇到以下两种情况:
- 当存在可以收发的 Channel 时,直接处理该 Channel 对应的
case; - 当不存在可以收发的 Channel 时,执行
default中的语句;
Go 语言设计的这个现象很合理。select 的作用是同时监听多个 case 是否可以执行,如果多个 Channel 都不能执行,那么运行 default 也是理所当然的。
select 在遇到多个 <-ch 同时满足可读或者可写条件时会随机选择一个 case 执行其中的代码。
select 与 switch 原理很相似,但它的使用场景更特殊,学习了本篇文章,你需要知道如下几点区别:
-
select 只能用于 channel 的操作(写入/读出/关闭),而 switch 则更通用一些;
-
select 的 case 是随机的,而 switch 里的 case 是顺序执行;
-
select 要注意避免出现死锁,同时也可以自行实现超时机制;
-
select 里没有类似 switch 里的 fallthrough 的用法;
-
select 不能像 switch 一样接函数或其他表达式。

浙公网安备 33010602011771号