变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间。
Go 语言是强类型静态语言,所以变量的声明与赋值方式与 PHP/Python 等动态语言相比有很大的区别。
动态语言(弱类型语言)是运行时才确定数据类型的语言,变量在使用之前无需申明类型,通常变量的值是被赋值的那个值的类型。比如Php、Asp、JavaScript、Python、Perl等等。
静态语言(强类型语言)是编译时变量的数据类型就可以确定的语言,大多数静态语言要求在使用变量之前必须生命数据类型。比如Java、C、C++、C#等。
Go 语言引入了关键字 var,并且将数据类型信息放在变量名之后,此外,变量声明语句不需要使用分号作为结束符,例如声明一个类型为 int 的变量 v1,示例如下:
var v1 int
// 也可以将若干需要声明的变量放置在一起
var (
v1 int
v2 string
)
Go 语言支持多种数据类型,这里先简单展示一下
var v1 int // 整型
var v2 string // 字符串
var v3 bool // 布尔类型
var v4 [10]int // 数组,数组元素类型为整型
var v5 struct ( // 结构体,成员变量 f 的类型为64位浮点型号
f float64
)
var v6 *int // 指针,指向整型
var v7 map[string]int // map(字典),key为字符串类型,value为整型
var v8 func(a int) int // 函数,参数类型为整型,返回类型为整型
变量在声明之后,系统会自动将变量值初始化为对应类型的零值,这里输出一下上面定义的变量。
如果变量名包含多个单词,Go 语言变量命名规则遵循驼峰命名法,即首个单词小写,每个新单词的首字母大写,如 userName
,但如果你的全局变量希望能够被外部包所使用,则需要将首个单词的首字母也大写。
如果声明变量时想要同时对变量值进行初始化,可以通过以下这些方式:
var v1 int = 10 // 方式一,常规的初始化操作
var v2 = 10 // 方式二,此时变量类型会被编译器自动推导出来
v3 := 10 // 方式三,可以省略 var,编译器可以自动推导出v3的类型
代码测试如下:
这里注意Go语言变量声明使用的符号是:=
,而不是=
。
变量进行初始化时,可以不必指定数据类型,这里让Go看上像是静态类型语言,但是与 PHP/Python/JavaScript 等动态语言不同的是,这个推导是在编译期做的,而不是运行时,因此 Go 语言还是不折不扣的静态语言。
另外,出现在 :=
运算符左侧的变量应该是未声明过的,否则会导致编译错误,比如下面这个写法:
var i int
i := 2
会出现如下的报错
在 Go 语言中,变量初始化和变量赋值是两个不同的概念,变量初始化及变量声明和赋值为一条语句,变量赋值则是先声明变量,再对其进行赋值,初始化只能执行一次,赋值则可以执行多次,下面是变量赋值过程:
// 变量赋值
var v10 int
v10 = 123
// 多重赋值
i,j = j,i
代码测试:
我们在使用传统的强类型语言编程时,经常会出现这种情况,即在调用函数时为了获取一个值,却因为该函数返回多个值而不得不定义一堆没用的变量。
匿名变量语法:
func GetName() (userName, nickName string) {
return "南歌", "EuanSu"
}
func AnonymousVariables() {
// 匿名变量
// GetName返回两个值,分别是username和nickName,
// 其中nickName是string类型,而GetName()函数中没有使用nickName,
// 此时nickName就是一个匿名变量,它不占用命名空间,不会分配内存,
// 因此不会产生任何开销。
_, nickName := GetName()
fmt.Printf("nickName value is %s\n", nickName)
}
每个变量在程序中都有一定的作用范围,称之为作用域。如果一个变量在函数体外声明,则被认为是全局变量,可以在整个包甚至外部包(变量名以大写字母开头)使用,不管你声明在哪个源文件里或在哪个源文件里调用该变量。在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量也是局部变量。
尽管变量的标识符必须是唯一的,但你可以在某个代码块的内层代码块中使用相同名称的变量,此时外部的同名变量将会暂时隐藏(结束内部代码块的执行后隐藏的外部同名变量又会出现,而内部同名变量则被释放),任何的操作都只会影响内部代码块的局部变量。
在 Go 语言中,常量是指编译期间就已知且不可改变的值,常量只可以是数值类型(包括整型、 浮点型和复数类型)、布尔类型、字符串类型等标量类型。Go 语言中,我们可以通过 const
关键字来定义常量(遵循 C 语言的约定)。
通过 const
关键字定义常量时,可以指定常量类型,也可以省略(编译时会自动推导),常见的常量定义方式如下:
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const ( // 通过一个 const 关键字定义多个常量,和 var 类似
size int64 = 1024
eof = -1 // 无类型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 无类型整型和字符串常量
代码执行测试:
由于常量的赋值是编译时期执行的,因此赋值的操作中不能出现任何需要运行才能得到结果的函数,例如如下语句就会导致编译错误:
func GetNumber() int {
return 100
}
const num = GetNumber()
GO语言预定义了常量:true、false 和 iota。
iota 比较特殊,认为是一个能够被编译器修改的常量,每一个 const 关键字出现时被重置为 0,每出现一次 iota,其所代表的数字就会自动加1.
const ( // iota 被重置为 0
c0 = iota // c0 = 0
c1 = iota // c1 = 1
c2 = iota // c2 = 2
)
const (
u = iota * 2; // u = 0
v = iota * 2; // v = 2
w = iota * 2; // w = 4
)
const x = iota; // x = 0
const y = iota; // y = 0
代码运行测试:
如果两个 const
的赋值语句的表达式是一样的,那么还可以省略后一个赋值表达式。因此,上面的前两个 const
语句可简写为:
const (
c0 = iota
c1
c2
)
const (
u = iota * 2
v
w
)
代码运行测试:
此外,常量还可以用于枚举。
枚举中包含了一系列相关的常量,比如下面关于一个星期中每天的定义。Go 语言并不支持其他语言用于表示枚举的 enum
关键字,而是通过在 const
后跟一对圆括号定义一组常量的方式来实现枚举。
下面是一个常规的 Go 语言枚举表示法,其中定义了一系列整型常量:
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays
)
代码运行测试:
和函数体外声明的变量一样,以大写字母开头的常量在包外可见(类似于 public
修饰的类属性),比如上面介绍的 Pi
、Sunday
等,而以小写字母开头的常量只能在包内访问(类似于通过 protected
修饰的类属性),比如 zero
、numberOfDays
等。
函数体内声明的常量只能在函数体内生效。