深入Go语言 - 4
2016-06-20 18:38
288 查看
本文介绍Go的声明和作用域。
声明用于常量、变量、类型、函数、标签和包。
每个非空标识符(identifier)必须声明。同一代码块中标识符只能声明一次。标识符不能同时声明在文件代码块和包代码块中。
空标识符为下划线 "_",它可以做为匿名占位符。
一个声明的标识符的作用域总结如下:
预声明的标识符的作用域是全局代码块如
顶层的(函数之外)的标识符, 用来声明常量、类型、变量或者函数(非方法), 这些标识符的作用域是包代码块
一个输入的包的包名的作用域是这个文件的文件代码块
用来表示方法 receiver、函数参数、结果变量的标识符的作用域是函数体
在一个函数内声明的常量或者变量的标识符的作用域起于ConstSpec 、 VarSpec之后(也就是标识符声明之后), 结束于包含它的最内层的代码块尾部
函数内声明的类型标识符始于 TypeSpec, 结束于包含它的最内层的代码块尾部
代码块中的标识符可以在内部的代码块中再次声明,但是内部的标识符和外部的标识符表示不同的对象,这个一定小心。
package
clause 并不是声明语句。 包名不能出现在任何作用域中 , 经常我们为了方便,声明一个变量的时候和包名一样,比如在引入
标签(label)作用域可以用于
定义一个未被使用的标签是非法的,这和函数内的定义未被使用的变量是一样的。
标签不会和其它同名的标识符冲突。
标签的作用域只在声明它的位置到函数体的尾部,不会作用于内部嵌套的函数。
空标识符前面已经提到了,下面是一些空标识符的应用。
预定义的标识符第一章中已经介绍了。
Go语言中没有 public、protect、private等关键字,如果想在其它包中访问当前包的标识符,
标识符应该具备下面两个条件,这和其它编程语言不太一样:
1、标识符名字的第一个字符应该是unicode upper case letter (Lu)
2、并且标识符声明在包代码块中,或者它是一个字段名或者方法名。
举个例子。在当前的main程序所在的目录中创建一个目录p,在里面创建一个文件t.go,定义两个包作用域的变量:
然后在main程序中尝试访问package p下的这两个变量,会发现只能访问
函数、常量、类型、struct、interface、方法都遵循这个法则。所以要想导出一个标识符,请首字母大写。
注意,这里要求的是首字母是unicode upper case letter,就是unicode分类为Lu的字符,对于Unicode字符,你需要知道哪些是大写字符,比如希腊字符也是有大小写的,中文不是大小写:
你可以在 这里 查看unicode
大写字符列表。
在常量定义中, iota 代表一个连续的未指定类型的整数常量。每当保留字const出现的时候,它都重置为0,后续的每个常量定义都会把它加一。 它常用来定义一组类似枚举的类型,比如月份、星期、颜色等。
如果使用表达式列表,同一表达式的iota的值是相同的,因为只有遇到新的ConstSpec才会增加。
Go语言中没有枚举类型,所以一般通过下面的方式定义枚举类型:
函数可以声明为签名,也可以定义方法体。
没有方法体的函数只有签名的函数可以声明在接口中,也可以声明包代码块中,此时标明方法是由外部实现的,比如汇编语言。
如果函数声明了返回类型,那么方法体中必须有相应的return语句。
匿名函数又叫函数字面量,它不包含函数名,可以用来赋值给变量(比如在一个函数内或者外赋值给一个变量)、或者直接调用(比如go语句中)。
方法声明类似函数声明,但是它包含一个接受者receiver。
在方法名的前面要声明一个额外的参数,这个参数是单一的,不可变的,作为receiver,
它的类型为
base type。
注意
方法名仅仅在类型T 或者 *T的 selector中显示。
receiver名不能和参数名或者返回参数重名:
方法名唯一。
对于struct类型,方法名和字段名必须唯一。
方法的特性和selector在下一章的表达式介绍。http://www.cfanz.cn/index.php?c=uc/main&id=16950
声明用于常量、变量、类型、函数、标签和包。
每个非空标识符(identifier)必须声明。同一代码块中标识符只能声明一次。标识符不能同时声明在文件代码块和包代码块中。
空标识符为下划线 "_",它可以做为匿名占位符。
一个声明的标识符的作用域总结如下:
预声明的标识符的作用域是全局代码块如
int、
true等
顶层的(函数之外)的标识符, 用来声明常量、类型、变量或者函数(非方法), 这些标识符的作用域是包代码块
一个输入的包的包名的作用域是这个文件的文件代码块
用来表示方法 receiver、函数参数、结果变量的标识符的作用域是函数体
在一个函数内声明的常量或者变量的标识符的作用域起于ConstSpec 、 VarSpec之后(也就是标识符声明之后), 结束于包含它的最内层的代码块尾部
函数内声明的类型标识符始于 TypeSpec, 结束于包含它的最内层的代码块尾部
代码块中的标识符可以在内部的代码块中再次声明,但是内部的标识符和外部的标识符表示不同的对象,这个一定小心。
package
clause 并不是声明语句。 包名不能出现在任何作用域中 , 经常我们为了方便,声明一个变量的时候和包名一样,比如在引入
net/http包的时候声明一个变量是
http,这是不对的,这会导致变量名会隐藏(shadow)包名。
标签作用域
标签(label)作用域可以用于 break、
continue、
goto语句,这在其它语言中也有定义,尽管不会推荐广泛应用。
i :=0 回来: i++ fmt.Println(i) ifi <5{ goto回来 }
定义一个未被使用的标签是非法的,这和函数内的定义未被使用的变量是一样的。
标签不会和其它同名的标识符冲突。
标签的作用域只在声明它的位置到函数体的尾部,不会作用于内部嵌套的函数。
空标识符和预定义标识符
空标识符前面已经提到了,下面是一些空标识符的应用。import( _ "net/http" ) const_ ="hello world" var_ =100 type_ []int type_struct{} type_interface{}
预定义的标识符第一章中已经介绍了。
输出标识符
Go语言中没有 public、protect、private等关键字,如果想在其它包中访问当前包的标识符,标识符应该具备下面两个条件,这和其它编程语言不太一样:
1、标识符名字的第一个字符应该是unicode upper case letter (Lu)
2、并且标识符声明在包代码块中,或者它是一个字段名或者方法名。
举个例子。在当前的main程序所在的目录中创建一个目录p,在里面创建一个文件t.go,定义两个包作用域的变量:
packagep varstr ="hello world" varStr ="Hello World"
然后在main程序中尝试访问package p下的这两个变量,会发现只能访问
Str,
str报错,说没有导出:
packagemain import( "fmt" "./p" ) funcmain() { fmt.Println(p.str) fmt.Println(p.Str) }
函数、常量、类型、struct、interface、方法都遵循这个法则。所以要想导出一个标识符,请首字母大写。
注意,这里要求的是首字母是unicode upper case letter,就是unicode分类为Lu的字符,对于Unicode字符,你需要知道哪些是大写字符,比如希腊字符也是有大小写的,中文不是大小写:
var一二三 ="123"//未输出 varΠ =3.1415926//输出
你可以在 这里 查看unicode
大写字符列表。
iota
在常量定义中, iota 代表一个连续的未指定类型的整数常量。每当保留字const出现的时候,它都重置为0,后续的每个常量定义都会把它加一。 它常用来定义一组类似枚举的类型,比如月份、星期、颜色等。const(// iota is reset to 0 c0 = iota// c0 == 0 c1 = iota// c1 == 1 c2 = iota// c2 == 2 ) const(// iota 重置为 0 a =1<<iota// a == 1 b =1<<iota// b == 2 c =3// c == 3 (iota 虽然没有使用,但是还是会增加) d =1<<iota// d == 8 ) const(// iota 重置为 0 u = iota*42// u == 0 (untyped integer constant) v float64=iota*42// v == 42.0 (float64 constant) w = iota*42// w == 84 (untyped integer constant) ) constx =iota// x == 0 (iota 重置为 0) consty =iota// y == 0 (iota 重置为 0)
如果使用表达式列表,同一表达式的iota的值是相同的,因为只有遇到新的ConstSpec才会增加。
const( bit0, mask0 =1<<iota,1<<iota-1// bit0 == 1, mask0 == 0, iota = 0 bit1, mask1 // bit1 == 2, mask1 == 1, iota = 1 _, _ // skips iota == 2 bit3, mask3 // bit3 == 8, mask3 == 7, iota =3 )
Go语言中没有枚举类型,所以一般通过下面的方式定义枚举类型:
typeWeekint varnames = [...]string{"星期一","星期二","星期三","星期四","星期五","星期六","星期日"} const( Monday Week = iota+1 Tuesday Wednesday Thursday Friday Saturday Sunday ) func(w Week) String()string{ ifw >0&& w <8{ returnnames[w-1] } return"非法的星期名" }
函数声明
函数可以声明为签名,也可以定义方法体。没有方法体的函数只有签名的函数可以声明在接口中,也可以声明包代码块中,此时标明方法是由外部实现的,比如汇编语言。
如果函数声明了返回类型,那么方法体中必须有相应的return语句。
匿名函数又叫函数字面量,它不包含函数名,可以用来赋值给变量(比如在一个函数内或者外赋值给一个变量)、或者直接调用(比如go语句中)。
f := func(x, yint)int{returnx + y } func(chchanint) { ch <- ACK }(replyChan) gofunc(chchanint) { ch <- ACK }(replyChan)
方法声明
方法声明类似函数声明,但是它包含一个接受者receiver。在方法名的前面要声明一个额外的参数,这个参数是单一的,不可变的,作为receiver,
它的类型为
T或者
*T,T叫做receiver
base type。
注意
T不能是指针类型或者皆苦类型,并且必须和方法声明在同一个包下。你想在自己的包下为标准库中的类型定义一个方法是不行的。
方法名仅仅在类型T 或者 *T的 selector中显示。
receiver名不能和参数名或者返回参数重名:
//错误 func(i IntArr) Say(iint) (iint) { return0 }
方法名唯一。
对于struct类型,方法名和字段名必须唯一。
方法的特性和selector在下一章的表达式介绍。http://www.cfanz.cn/index.php?c=uc/main&id=16950
相关文章推荐
- Django的基本命令
- django全貌
- Django开发(一)
- Google推荐的图片加载库Glide介绍
- 使用go的ssh包快速打造一个本地命令行ssh客户端
- Google Guava缓存实现接口的限流
- Google Guava缓存实现接口的限流
- 为什么学习go语言编程?
- Django的列表反序
- golang ide 升级
- Dashgo多种运动方式
- Ubuntu14.04 Sogou输入法设置
- golang学习———方法别名(1)
- Django中新版本变动和版本不同的各种坑 (持续更新)
- STL源码剖析——stl_algobase.h
- go语言学习之路 二:变量
- 带你感受小而美的看板协作工具leangoo的魅力
- visible invisible gone 区别
- 利用ZXing生成带LOGO的二维码图片
- mgo insert数据的时候数据插入的不全