一、命名:
Go语言中的命名包括函数名、变量名、常量名、类型名、语句标号和包名等等。一个名字必须以一个字母或下划线开头,区分大小写。
Go语言的关键字有25个,不能用于命名:
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
此外,还有30多个预定义的名字,如int、true等也不能用于命名:
内建常量: true false iota nil
内建类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
内建函数: make len cap new append copy close delete
complex real imag
panic recover
Go语言的推荐命名方式为驼峰式,即通过大小写对几个单词进行分隔,例如QuoteRuneToASCII和parseRequestLine。
二、声明:
和所有C系列语言一样,Go语言中的声明也是为了定义程序中的实体对象以及部分或全部属性。其中,变量声明:var、常量声明:const、类型声明:type、函数体声明:func。
package main
import "fmt"
const boilingF = 212.0
type NewInt int
func main() {
var f = boilingF
var c = (f - 32) * 5 / 9
fmt.Printf("boiling point = %g°F or %g°C\n", f, c)
}
上述代码为《Go语言圣经》中的代码,分别展示了 const、type、func、var的用法。其中type关键字的主要作用是声明一个类型的别名,主要是为了解决代码重构中麻烦的变量名变更问题,尤其是在跨平台迁移时应用颇多。此方法和c++中的typedef十分类似。
三、变量
在第二节中,展示了四种声明,这里着重记录一下变量的相关细节。
变量的声明:
变量声明的一般语法为: var 变量名字 类型 = 表达式
变量声明的简短语法为: 变量名字 := 表达式
var a int //声明一个int类型的变量a,当不对变量进行赋值的时候,int型一般初始化为0
var a,b int //声明两个int类型的变量,a、b
var a int =3 //声明一个int类型的变量a,并将a赋值为3
var a,b,c = true,2,"four" //声明三个变量,其中a为bool类型,b为int型,c为string类型
a:=100 /*变量声明的简短形式,:= 符号可以自动去匹配表达式的类型,然后
赋予给变量,并将表达式的值赋给变量,此方法类似于c++11 中的
auto关键字*/
其中,变量的简短声明也可以在一行中声明多个变量,同样,在声明的过程中会根据对应的表达式进行自动的类型匹配,并赋值,例如:
i,j := 0,1
四、指针
作为C系列的编程语言,Go也继承了指针,这一C语言和C++最重要的类型。和所有C系列的指针一样,Go语言的指针也是指向一块对应类型的内存地址空间,并可以通过指针来访问这块地址空间所保存的变量。
指针的声明:
x := 1
p := &x //等价于 p *int =&x
上述代码中的p即为指针变量,其指向了变量x的地址空间,可以通过解引用:*p对这个变量进行访问。
Go语言中的指针和C++中的指针有一些区别,如:
C++里指针可以直接进行算术运算(如+,-,++,--),但是Go里的指针不行。Go语言中的指针并不能进行偏移和运算,这里主要是为了安全着想。
Go语言指针的一个非常重要的应用是切片(slices),Go语言的切片,由指向起始元素的原始指针、元素数量和容量组成(和C++中的vector数组非常相似)
五、new函数
Go语言中的new函数主要方法是创建变量,它和C++中的new十分类似,主要作用是分配内存。但是Go语言中的new并不会初始化内存,而是将内存置零,然后返回内存的地址(每次调用new函数,都会返回一个随机的地址变量),返回的类型为指针。
new 函数的一般用法是:
变量名 (指针类型) = new(和指针匹配的类型名)
p *T = new(T)
p := new(int) //此时*p 的值为0,且该语句等价于 p *int = new(int)
六、赋值
Go语言的赋值和其他语言区别不大,都是用 ”=“ 作为赋值符号,任何变量、常量(在初始化的时候)、指针、结构体中的字段等等都可以被赋值,且表达式也和其他语言一致
x = 1 //对变量赋值
*p = true //通过指针间接赋值
person.name = "Bob" //结构体中的字段进行赋值
conunt[i] = count[I-1]*I //对数组进行赋值
关于赋值,特定的二元算术符可以和赋值符号合并成一个简洁形式,如 +=、-=、*=、/=。
需要注意的是,在Go语言中,自增自减(++、--)是语句,而不是表达式,所以是不能放到赋值符号的右边的,且++、-- 符号只能放到变量的右边(Go语言并不会出现C++中的经典问题:i++与++i的区别,因为Go语言中只存在i++)
x = i++ //这是错误的写法
与python类似,Go语言支持元组赋值,即允许同时更新多个变量的值。在赋值前,赋值语句的右边的所有表达式将会先进行求值,然后统一更新左边的变量的值。因为这个特性,Go语言可以用一行代码进行交换变量的值:
x , y = 1 ,2
x , y = y , x
在Go语言中,有些表达式会产生多个值,比如一个表达式可以有一个或多个返回值。这时,当调用这样的函数时,赋值符号的左边的变量数必须和右边返回值的数量相等,或者可以用 ”_“ 符号进行占位(该符号表示对应的值会被丢弃)
f, err = os.Open("foo.txt") //os.Open函数会返回两个值,其中第二个返回值为error类型的错误,;表达某种错误类型
f , _ = os.Open("foo.txt") //该语句表示错误返回值会被丢弃
需要注意的是,在Go语言中map类型的返回值可以是两个(当map的返回值为两个的时候,第一个值就是map的value,第二个值用于判断map的键是否存在,是一个bool型变量。),也可以是一个(此时,和C++中的map基本相同,当键不存在的时候,会返回零值)。
v , ok = m[key] //v表示map中key键对应的值,ok表示key键是否存在
v = m[key] //此时,当key键不存在的时候,会返回一个零值。