プログラム ステートメント |
インポート、package |
##プログラムエンティティの宣言と定義##chan、const、func、interface、map、struct、type、var |
|
プログラム制御フロー
go、select、break、case、 continue、default、defer、else、fallthrough、for、goto、if、range、return、switch |
|
在Go语言中,程序实体的声明和定义是建立在其数据类型的体系之上的。例如关键字chan、func、interface、map和struct,分别于Go语言的复合数据类型Channel(通道)、Function(函数)、Interface(接口)、Map(字典)和Struct(结构体)相对应。
程序控制流程的关键字,一共15个。其中go和select,这两个主要用于Go语言并发编程。
3、字面量
简单来说,字面量就是值的一种标记法。但是,在Go中,字面量的含义要更加广泛一些。
Go语言代码中用到的字面量有以下3类:
1、表示基础数据类型值的各种字面量。例如,表示浮点数类型值的12E-3。
2、构造各种自定义的复合数据类型的类型字面量。例如,下面表示一个名称为Person的自定义结构体类型:
3、表示复合数据类型的值的复合字面量
被用来构造类型Struct(结构体)、Array(数组)、Slice(切片)和Map(字典)的值。例如,下面的字面量用于表示上面名称为Person的结构体类型的值:
注意:
对复合字面量的每次求值都会导致一个新的值被创建。因此,如上该复合字面量每被求值一次就会创建一个新的Person类型的值。
Go语言不允许在一个此类的复合字面变量中,出现重复的键。如下都是错误,无法通过编译,因为键都有重复。
4、类型
一个类型确定了一类值的集合,以及可以在这些值上施加的操作。类型可以由类型名称或者类型字面量指定,分为基本类型和复合类型,基本类型的名称可以代表其自身。
如上声明了一个类型为string(基本类型中的一个)、名称为bookName的变量。
其他基本类型(预定义类型)有bool、byte、rune、int/uint、int8/uint8、int16/uint16、int32/uint32、int64/uint64、float32、float64、complex64和complex128。除了bool和string之外的其他基本类型也叫做数值类型。
复合类型一般由若干(也包括零)个其他已被定义的类型组合而成。复合类型有Channel(通道)、Function(函数)、Interface(接口)、Map(字典)、Struct(结构体)、Slice(切片)、Array(数组)和Pointer(指针)。
Go语言中的类型又可以分为静态类型和动态类型。一个变量的静态类型是指在变量声明中给出的那个类型。绝大多数类型的变量都只有静态类型。唯独接口类型的变量例外,它除了拥有静态类型之外,还拥有动态类型(接口类型在后面会讲到)。
每一个类型都会有一个潜在类型。如果这个类型是一个预定义类型(也就是基本类型),或者是一个由类型字面量构造的复合类型,那么它的潜在类型就是它自身。如string类型的潜在类型就是string类型,上面自定义的Person类型的潜在类型就是Person。如果一个类型并不属于上述情况,那么这个类型的潜在类型就是类型声明中的那个类型的潜在类型。
如下声明一个自定义类型
如上可以把类型MyString看作string类型的一个别名类型,那么MyString类型的潜在类型就是string类型。Go语言基本数据类型中的rune类型可以看作是uint32类型的一个别名类型,其潜在类型就是uint32。
注意:
- 类型MyString和类型string是两个不相同的类型。不能将其中一个类型的值赋给另一个类型的变量。
- 别名类型与它的源类型的不同仅仅体现在名称上,它们的内部结构是一致的;下面的类型转换的表达式都是合法的:MyString(“ABC”) 和string(MyString(“ABC”))。这种类型转换并不会创建新的值。
一个类型的潜在类型具有可传递性,如下:
则类型isString的潜在类型就是string类型。
这里声明一个类型,如下:
##**注意:**MyStrings 型の基になる型は [3]string ではありません。 [3] string は、定義済み型でも型リテラルから構成される複合型でもありませんが、要素型が string である配列型です。
上記の定義によれば、MyStrings 型の潜在的な型は、[3]string の潜在的な型文字列であることがわかります。 Go 言語では、配列型の潜在的な型によって、その型の変数にどの型の要素を格納できるかが決まると規定されています。
5. 演算子
演算子は、特定の算術演算または論理演算を実行するために使用される記号です。 (C言語の演算子と似ているのでここでは詳しく説明しません) ただし、Go言語には三項演算子がないため、単項演算子を除いてすべての演算子は二項演算子でなければなりません。 Go言語には算術演算子、比較演算子、論理演算子、アドレス演算子、受付演算子など合計21個の演算子があります。
#シンボル | 説明 | 例 |
|
|
|
&&&
ロジックと操作。二項論理演算子 |
true && false //式の結果は false です |
|
==
等価判定演算です。バイナリ、比較演算子 |
"abc" == "abc" //結果は true |
|
#!=
不等判定演算。バイナリ、比較演算子 |
"abc" != "Abc" //結果は true |
| ##2a4c94a0a3bae54371d2dc7493330786
は判定演算よりも大きいです。バイナリ、比較演算子 | 3 > 2 //式の結果は true です |
| >=
は以上です。バイナリ、比較演算子 | 3 >= 2 //式の結果は true |
|
# は合計、1 元は 2 元、算術を意味します演算子 | 1 //結果は 1 (1 2) //結果は 3 |
| -
は差を表し、1 元です再びバイナリです。算術演算子 | -1 //結果は -1 (1 – 2) //結果は -1 |
| \
# です##ビットごとの OR 演算、バイナリ、算術演算子
5 \ 11 //式の結果は 15 |
|
^ |
ビット XOR を押してください、1 つの要素はバイナリ、算術演算子
5 | 11//結果は 14 (5)//結果は -6 |
* |
製品または値、1 元、2 バイナリ、算術、アドレス
*p //値演算 |
|
/ |
商演算、バイナリ、算術演算子
10 / 5 //式の結果は2 |
|
% |
剰余演算、バイナリ、算術演算子
12 % 5 //式の結果は2 |
|
21f39dc344a5829efe337c471f30da17> |
| ビット単位の右シフト演算、バイナリ、算術演算子
4 >> 2 //式の結果は1 |
##& |
ビット単位のAND演算、単項、二項、算術, address |
&v //アドレス演算
|
&^ |
# #ビット単位のクリア演算、バイナリ、算術演算子 |
5 &^ 11 //式の結果は 4
|
! |
論理演算非演算、単項論理演算子 |
!b //If bは true、結果は false
| ##0bf8e58812ca5907ffc26208f2ae8fd5> & &^
4 |
+ - \ ^ |
3 |
== != 8056e466eb4ac2e45f0ee1fdc891a78a >= |
2 |
&& |
1 |
|
扩展知识:表达式
基本表达式
(1) 使用操作数来表示;
(2) 使用类型转换来表示;
(3) 使用内建函数调用来表示;
(4) 一个基本表达式和一个选择符号组成选择表达式;
例如,如果在一个结构体类型中存在字段f,我们就可以在这个结构体类型的变量x上应用一个选择符号来访问这个字段f,即x.f。其中,.f就是一个选择符号。注意:前提是这个变量x的值不能是nil。在Go语言中,nil用来表示空值。
(5) 一个基本表达式和一个索引符号组成索引表达式;
索引符号由狭义的表达式(仅由操作符和操作数组成)和外层的方括号组成,例如[]int{1,2,3,4,5}[2]就是索引表达式。
Go语言允许如下的赋值语句:
如上a为字典类型,x为字典的键。该索引表达式的结果是一对值,而不是单一值。第一个值的类型就是该字典类型的元素类型,而第二个值则是布尔类型。与变量ok绑定的布尔值代表了在字典类型a中是否包含了以x为键的键值对。如果在a中包含这样的键值对,那么赋给变量ok的值就是true,否则就为false。
**注意:**虽然当字典类型的变量a的值为nil时,求值表达式a[x]并不会发生任何错误,但是在这种情况下对a[x]进行赋值却会引起一个运行时恐慌( Go语言异常)。
(6) 一个基本表达式和一个切片符号组成切片表达式;
切片符号由2个或3个狭义的表达式和外层的方括号组成,这些表达式之间由冒号分隔。切片符号作用与索引符号类似,只不过索引符号针对的是一个点,切片符号针对的是一个范围。例如,要取出一个切片[]int{1,2,3,4,5}的第二个到第四个元素,那么可以使用切片符号的表达式[]int{1,2,3,4,5}[1:4],该结果还是一个切片。
切片表达式a[x:y:z],a是切片符号[x:y]的操作对象。其中,x代表了切片元素下界索引,y代表了切片的元素上界索引,而z则代表了切片的容量上界索引。约束如下:
0 <= 元素下界索引 <= 元素上界索引 <= 容量上界索引 <= 操作对象的容量
设a的值为[]int{1,2,3,4,5},则切片表达式a[:3]等同于a[0:3],这是因为切片符号的元素下界索引的默认值为0,相应的元素上界的索引的默认值为操作对象的长度值或容量值,即切片表达式a[3:]等同于a[3:5]。同样,切片表达式a[:]等同于复制a所代表的值并将这个复制品作为表达式的求值结果。
注意: UTF-8 编码格式会以3个字节来表示一个中文字符,而切片操作是针对字节进行的。
如果有“Go并发编程实战”的字符串类型的变量a,那么切片表达式a[1:3]的结果不是“o并”,而a[1:5]的结果才是“o并”。
(7) 一个基本表达式和一个类型断言符号组成;
类型断言符号以一个英文句号为前缀,并后跟一个被圆括号括起来的类型名称或类型字面量。类型断言符号用于判断一个变量或常量是否为一个预期的类型,并根据判断结果采取不同的响应。例如,如果要判断一个int8类型的变量num是否是int类型,可以这样编写表达式:interface{}(num).(int)。
对于一个求值结果为接口类型值的表达式x和一个类型T,对应的类型断言为:
该表达式的作用是判断“x不为nil且存储在其中的值是T类型的”是否成立。
如果T不是一个接口类型,那么x.(T)会判断类型T是否为x的动态类型(一个变量的动态类型就是在运行期间存储在其中的值的实际类型);而这个实际类型必须是该变量声明的那个类型的一个实现类型,否则就根本不可能在该变量中存储这一类型的值。所以类型T必须为x的类型的一个实现类型,而在Go语言中只有接口类型可以被其他类型实现,所以x的求值结果必须是一个接口类型的值。
所以上面表达式interface{}(num).(int)中表达式interface{}(num)的含义就是将变量num转换为interface{}类型的值(即它的结果值是接口类型的),而这刚好符合前面的定义。
知识点: interface{}是一个特殊的接口类型,代表空接口。所有类型都是它的实现类型。
在对变量的赋值或初始化的时候,也可以使用类型断言,如下:
当使用类型断言表达式同时对两个变量进行赋值时,如果类型断言成功,那么赋给第一个变量的将会是已经被转换为T类型的表达式x的求值结果,否则赋给第一个变量的就是类型T的零值。布尔类型会被赋给变量ok,它体现了类型断言的成功(true)与否(false)。
注意: 在这种场景下,即使类型断言失败也不会引发运行时恐慌。
(8) 一个基本表达式和一个调用符号组成。
调用符号只针对于函数或者方法。与调用符号组合的基本表达式不是一个代表代码包名称(或者其别名)的标识符就是一个代表结构体类型的方法的名称的标识符。调用符号由一个英文句号为前缀和一个被圆括号括起来的参数列表组成,多个参数列表之间用逗号分隔。例如,基本表达式os.Open(“/etc/profile”)表示对代码包os中的函数Open的调用。
可变长参数
如果函数f可以接受的参数的数量是不固定的,那么函数f就是一个能够接受可变长参数的函数,简称可变参函数。在Go语言中,在可变参函数的参数列表的最后总会出现一个可变长参数,这个可变长参数的类型声明形如…T。Go语言会在每次调用函数f的时候创建一个切片类型值,并用它来存放这些实际函数。这个切片类型值的长度就是当前调用表达式中与可变长参数绑定的实际参数的数量。
可变参函数appendIfAbsent声明如下(函数体省略):
针对此函数的调用表达式如下:
其中,与可变参数t绑定的切片类型值为[]string{”C”,”B”,”A”},包含了实际参数”C”,”B”和”A”。
也可以直接把一个元素类型为T的切片类型值赋给…T类型的可变长参数,如下调用:
或者如果有一个元素类型为stirng的切片类型的变量s的话,如下调用:
对于将切片类型的变量赋给可变长参数的情况,Go语言不会专门创建一个切片类型值来存储其中的实际参数。因为,这样的切片类型值已经存在了,可变长参数t的值就是变量s的值。
【相关推荐:Go视频教程、编程教学】