本文介绍Go语言的常量和变量的语言细节。
只有数值类型和字符串类型才可以作为常量。
数值类型包括 布尔类型、rune类型、各种整型、浮点类型、复数。
常量值既可以是数值类型的字面值,也可以是字符串字面值,以及常量的等价形式, 如:
4 * 5
int(10.0)
unsafe.Sizeof
、 cap
、 len
true
和 false
赋值给bool类型的常量 iota
用变量赋值给常量是不允许的:
varvs ="hello world" consts = vs//错误
常量的命名还是遵循前一篇文章的介绍,所有你看到一些"奇怪"的常量名不要觉得奇怪:
constπ =3.1415926 constΠ =3.1415926
常量可以不声明类型(untyped), 它会根据常量值设置默认的类型,默认类型为:
在需要类型的上下文中,常量可以 隐式 转换成相应的类型:
varv1int= i varv2float32= i varv3complex64= i
注意不同类型的变量是不能转换的:
varv4float64= v2
你不能将一个不能隐式转换成常量类型的值赋值给常量,比如下面的例子中 2147483648.0
不能赋值给int32, 溢出了:
consti2int32=2147483648.0
Go对常量的底层实现有限制:
声明多个变量的时候可以将声明放在一起:
const( i =1 s = "hello word" )
或者将多个常量的定义放在一行中:
consti1, i2, i3 =0,1,"hello world"
常量也可以定义在函数中:
funcG() { constt =100 }
变量代表一个值的存储位置,每个值都有类型。
变量在声明的时候如果同时有赋值操作,那么类型可以省略,因为可以根据值推断出来:
vari1int=100 vari2 =100
类似于常量定义,你可以同时声明多个变量:
var( i3 =120 i4 = "hello world" )
或者一行声明多个变量:
vari5, i6, i7 =100,"hello world",true vari8, i9, i10int
在上面的例子中i8、i9、i10都是 int类型,所以将类型写在最后面,下面的写法是不允许的:
vari11int, i12int, i13int//错误
下面的语句也是非法的,因为声明的变量和赋值列表的数值数量必须一样:
vari14, i15, i16 =100,200//错误 vari17, i18, i19int=100,200//错误
如果变量在声明的时候同时初始化,那么它就可以简化。比如
vari1, i2 =100,"hello world"
可以简化为
i1, i2 :=100,"hello world"
记住,这个简写方法 只能用在函数中 ,函数之外的变量声明不能简写,下面的写法是错误的。
packagemain s := "中国" funcmain() { }
不像普通的变量声明,简写方式声明的变量可以"重新声明"已有变量,只要保证有一个新的变量在变量列表中即可,当然“重新声明”的变量和原有变量的类型相同。看下面的例子就容易理解了:
funcmain() { varf *os.File f, err := os.Open("dive-into-go.pdf") fmt.Println(f, err) }
这个例子中 f
变量重新被声明了,程序正常编译,没有错误,这是因为 err
是新的变量。
下面这个例子就编译不过,因为第4行没有新的变量定义。
funcmain() { varf *os.File varerr error f, err := os.Open("dive-into-go.pdf") fmt.Println(f, err) }
不能用简写方法赋值给一个结构体的字段(field):
typeMyFilestruct{ varF *os.File } funcmain() { varmf MyFile //var err error mf.F, err := os.Open("dive-into-go.pdf") fmt.Println(f, err) }
注意,简写方法有时候会迷惑你,因为它可能 shadow
一个变量,而且正常编译通过:
x :=100 func() { x :=200 fmt.Println(x) //200 }() fmt.Println(x) //100
在上面的例子中,如果本意是通过一个方法修改变量x的值为200的话,最终打印结果可能是100,因为第三行实际是声明了一个新的变量。
你可以通过 vet
工具检查代码中是否包含 shadow
的代码:
go tool vet -shadow main8.go
输出结果为:
main8.go:8:declarationofxshadowsdeclarationatmain8.go:6:
变量和常量都可以定义在函数内或者包下,但是如果函数内的变量没有被使用,则会编译出错,这是Go语言有意这样设计的。包下的变量和常量,函数内的常量没有这个限制。
参考
* http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#short_vars
静态类型(static type)是变量声明的时候的声明类型,在变量声明、new方法创建对象时或者结构体(struct)的元素的类型定义,参数类型等。
接口(interface)类型的变量还有一个动态类型,它是运行时赋值给这个变量的具体的值的类型(当然值为nil的时候没有动态类型)。一个变量的动态类型在运行时可能改变,这主要依赖它的赋值。
varxinterface{}// x 为零值 nil,静态类型为 interface{} varv *T// v 为零值 nil, 静态类型为 *T x =42// x 的值为 42,动态类型为int, 静态类型为interface{} x = v // x 的值为 (*T)(nil), 动态类型为 *T, 静态类型为 *T