Go的语言符号又称为词法元素,共包括5类内容: 标识符(identifier) 关键字(keyword) 字面量(literal) 分隔符(delimiter) 操作符(operator) 它们可以组成各种表达式和语句,而后者都无需以分号结尾。
1.标识符
标识符可以表示程序实体,前者即为后者的名称。 在一般情况下,同一个代码块中不允许出现同名的程序主体。
在Go中,变量、常量、函数和类型声明可统称为程序实体,而它们的名称统称为标识符。 标识符可以是Unicode字符集中任意能表示自然语言文字的字符、数字以及下划线(_)。标识符不能以数字或下划线开头。
实际上,标识符的首字符的大小写控制着对应程序实体的访问权限。 如果标识符的首字符是大写形式,那么它所对应的程序实体就可以被本代码之外的代码访问到,也称之为可导出或公开的; 否则,对应的程序实体就只能被本包内的代码访问,也成为不可导出的或包私有的。 要想成为可导出的程序实体,还需要额外满足以下两个条件。 a.程序实体必须是非局部的。局部的程序实体是指:它被定义在了函数或结构体的内部。 b.代码包所属目录必须包含在GOPATH中定义的工作区目录中。
使用不同代码包中的程序实体需要用到限定的标识符。比如:os.O_RDONLY。 另外,Go中还存在着一类特殊的标识符,叫做预定义标识符,它们是在Go源码中声明的。 这类标识符包括以下几种: a.所有基本数据类型的名称。 b.接口类型error。 c.常量true、false和iota。
所有内建函数的名称,即append、cap、close、complex、copy、delete、 imag、len、make、new、panic、print、println、real和recover。
这里强调一下空标识符,它由一个下划线_表示,一般用在变量声明或代码包导入语句中。 若在代码中存在一个变量x,但是却不存在任何对它的使用,则编译器会报错。 如果在变量x的声明代码后添加这样一行代码:
就可以绕过编译器的检查,使它不产生任何编译错误。 这是因为这段代码确实用到了变量x,只不过它没有在变量x上进行任何操作,也没有将它赋值给任何其他变量。 空标识符就像一个垃圾桶。在相关初始化工作完成之后,操作对象就会被弃之不用。
2.关键字
关键字是被编程语言保留的字符序列,编程人员不能把他们用作标识符。因此,关键字也称为保留字。 Go的关键字可以分为3类,包括用于程序声明的关键字、用于实体声明和定义的关键字,以及用于程序流程的关键字。
Go的关键字自共有25个,其中与并发编程有关的关键字有go、chan和select。 需要说明一下的是关键字type——类型声明。我们可以使用它声明一个自定义类型:
这里把名为myString的类型声明为string类型的一个别名类型。 反过来说,string类型是myString类型的潜在类型。 虽然类型及其潜在类型是不同的两个类型,但是它们的值可以进行类型转换,而且不会产生新值也没有什么代价。
自定义的类型一般都会基于Go中的一个或多个预定义类型。 如果为自定义类型关联若干办法(函数的变体),那么还可以让它成为某个或某些接口类型的实现类型。 另外,还有一个比较特殊的类型,叫做空接口。它的类型字面量是interface{}。在Go语言中,任何类型都是空接口类型的实现类型。
3.字面量
简单来说,字面量就是值的一种标记法。但是,在Go中,字面量的含义要更加广泛一些。 我们常常用到的字面量有以下三类: (1)用于表示基础数据类型值的各种字面量。例如:表示浮点数类型值的12E-3. (2)用于构造各种自定义的复合数据类型的类型自变量。例如下面的字面量定义了一个名称为Name的结构类型。
type Name struct {
Forename string
Surname string
}
(3)用于表示复合数据类型的值的复合字面量,它可以是用来构造struct(结构体)、array(数组)、slice(切片)和map(字典)类型的值。 复合字面量一般由字面类型以及被花括号包裹的复合元素的列表组成。 字面类型指的是复合数据类型的名称。例如:复合字面量构造出一个Name类型的值。
Name{Forename:"Rebert",Surname:"Hao"}
其中Name表示这个值的类型,紧随其后的就是由键值对表示的复合元素列表。
4.操作符
操作符,也成为运算符。它是用于执行特定算术或逻辑操作的符号,操作的对象称为操作数。
点击这里 |
点击这里 |
点击这里 |
符号 |
说明 |
示例 |
|| |
逻辑或,二元操作符,也是逻辑操作符 |
true||fale //true |
&& |
逻辑与,二元操作符,也是逻辑操作符 |
true&&false //flase |
== |
相等,二元操作符,也是比较操作符 |
"abc"=="abc" //true |
!= |
不相等,二元操作符,也是比较操作符 |
“abc”!="Abc" //true |
< |
小于,二元操作符,也是比较操作符 |
1 < 2 //true |
<= |
小于或等于,二元操作符,也是比较操作符 |
1 <= 2 //true |
> |
大于,二元操作符,也是比较操作符 |
3 > 2 //true |
>= |
大于或等于,二元操作符,也是比较操作符 |
3 >= 2 //true |
+ |
求和,既是一元操作符也是二元操作符,也属于算术操作符,若是一元操作符不会对原值产生任何影响 |
1 + 2 //3 |
- |
求差,既是一元操作符也是二元操作符,也属于算术操作符,若是一元操作符,则表示求反操作 |
1 - 2 // -1 |
| |
按位或操作,它是二元操作符,同时也属于算术操作符 |
5 | 11 //15 |
^ |
按位异或操作,既是一元操作符也是二元操作符,若是一元操作符表示按位补码操作,也属于算数操作符 |
5 ^ 11 //14 |
* |
求乘积操作,既是一元操作符也是二元操作符,也属于算术操作符和地址操作符,若为地址操作符则表示取值操作 |
*p //若p为指向整数类型值为2的指针类型,则结果为2 |
/ |
求商操作,二元操作符,也属于算术操作符 |
10 / 5 //2 |
% |
求余数操作,二元操作符,也属于算术操作符 |
12 % 5 //2 |
<< |
按位左移操作,二元操作符,也属于算术操作符 |
4 << 2 //16 |
>> |
按位右移操作,二元操作符,也属于算术操作符 |
4 >> 2 //1 |
& |
按位与,既是一元操作符也是二元操作符,,同时也属于算术操作符和地址操作符,若为地址操作符,表示取值操作 |
&v //标识符v所代表的值在内存中的地址 |
&^ |
按位清除操作,二元操作符,也属于算术操作符 |
5 &^ 11 //4 |
! |
逻辑非,一元操作符,也属于逻辑操作符 |
!b //如果b为false,则结果为true |
<- |
接收操作,一元操作符,也属于接收操作符 |
<- ch //接收一个byte类型值 |
Go的操作符一共由21个,并分为了5类:算术操作符、比较操作符、逻辑操作符、地址操作符和接收操作符。
当一个表达式中存在多个操作符的时候,就涉及操作顺序的问题。 在Go中,一元操作符拥有最高的优先级,二元操作符的优先级如下表所示:
数字越大意味着优先级就越高,如果一个表达式中出现了处于相同优先级的多个操作符, 且这些操作符之间仅存在操作数,那么就会按照从左到右的顺序进行操作。 当然可以使用圆括号显式改变原有的操作顺序,例如表达式a << (4 * b) & c, 表达式虽然操作符的优先级一样,但是4 * b会先被求值。
需要注意的是,++和--是语句而不是表达式,因而它们不存在于任何操作符优先级层次之内。例如(*p)--等于*p--。
5.表达式
表达式是把操作符和函数作用于操作数的计算方法。 在Go中,表达式是构成具有词法意义的代码的最基本元素。
关于类型断言,有两点需要注意: (1)如果v1是一个非接口值,那么必须在做类型断言之前把它转换成接口值。 因为Go中的任何类型都是空接口类型的实现类型,所以一般会这样:interface{}(v1).(I1).
(2)如果类型断言的结果为否,就意味着该类型断言是失败的。失败的; 失败的类型会引发异常,解决方法是: var i1,ok = interface{}(v1).(I1) 这里声明并赋值了两个变量,其中ok是布尔类型的变量,它的值体现了类型判断的成败。 如果成功,i1就会是经过类型转换后的I1类型的值,否则它将会是I1类型的零值(或默认值)。 如此一来,当类型断言失败时,运行异常也就不会发生。
关键字var用于变量的声明。在它和等号=之间可以由多个逗号隔开的变量名。 这种在一条语句中同时为多个变量赋值的方式叫做平行赋值。 另外,如果在声明变量的同时进行赋值,那么等号左边的变量类型可以省略
var i1 I1
var ok bool
i1,ok = interface{}(v1).(I1)
另一方面,上面那条语句还可以简写成:
i1,ok :=interface{}(v1)(I1)
这种简写方式只能出现在函数中。有了符号:=,关键字var就可以省略,这叫做短变量声明。
|
请发表评论