转载

深入Go语言 - 2

本文介绍Go语言的常量和变量的语言细节。

常量

只有数值类型和字符串类型才可以作为常量。

数值类型包括 布尔类型、rune类型、各种整型、浮点类型、复数。

常量值既可以是数值类型的字面值,也可以是字符串字面值,以及常量的等价形式, 如:

  1. 常量表达式, 如 4 * 5
  2. 转换结果是常量, 如 int(10.0)
  3. 内建函数的返回值, 如 unsafe.Sizeofcaplen
  4. 复数、实数和虚数的应用
  5. truefalse 赋值给bool类型的常量
  6. 内建的 iota

用变量赋值给常量是不允许的:

varvs ="hello world" consts = vs//错误 

常量的命名还是遵循前一篇文章的介绍,所有你看到一些"奇怪"的常量名不要觉得奇怪:

constπ =3.1415926 constΠ =3.1415926 

常量可以不声明类型(untyped), 它会根据常量值设置默认的类型,默认类型为:

  • bool
  • rune
  • int
  • float64
  • complex128
  • string

在需要类型的上下文中,常量可以 隐式 转换成相应的类型:

varv1int= i varv2float32= i varv3complex64= i 

注意不同类型的变量是不能转换的:

varv4float64= v2 

你不能将一个不能隐式转换成常量类型的值赋值给常量,比如下面的例子中 2147483648.0 不能赋值给int32, 溢出了:

consti2int32=2147483648.0 

Go对常量的底层实现有限制:

  • Represent integer constants with at least 256 bits.
  • Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed exponent of at least 32 bits.
  • Give an error if unable to represent an integer constant precisely.
  • Give an error if unable to represent a floating-point or complex constant due to overflow.
  • Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.

声明多个变量的时候可以将声明放在一起:

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 
原文  http://colobu.com/2016/06/16/dive-into-go-2/
正文到此结束
Loading...