您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Go語言有哪幾類詞法元素”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Go語言有哪幾類詞法元素”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
Go語言的詞法元素有5類:1、標識符,由若干字母(由Unicode編碼即可)、下劃線和數字組成的字符序列;2、關鍵字,是被編程語言保留而不讓編程人員作為標識符使用的字符序列,也可以稱為保留字;3、操作符,是用于執行特定算術運算或邏輯操作的符號;4、分隔符;5、字面量,是值的一種標記法。
Go語言的語言符號又稱為詞法元素,共包括5類:標識符(identifier)、關鍵字(keyword)、操作符(operator)、分隔符(delimiter)、以及字面量(literal),它們是組成Go語言代碼和程序的最基本單位。
一般情況下,空格符、水平制表符、回車符和換行符都會被忽略,除非它們作為多個語言符號之間的分隔符的一部分。在Go語言中不需要顯示地插入分號,在必要時,Go語言會自動為代碼插入分號以進行語句分隔。
Go語言代碼由若干個Unicode字符組成,Go語言的所有源代碼都必須由Unicode編碼規范的UTF-8編碼格式進行編碼(也就是說編寫的Go語言源碼文件必須是UTF-8編碼格式的)。
Go語言的語言符號又稱為詞法元素,共包括5類:標識符(identifier)、關鍵字(keyword)、操作符(operator)、分隔符(delimiter)、以及字面量(literal)。一般情況下,空格符、水平制表符、回車符和換行符都會被忽略,除非它們作為多個語言符號之間的分隔符的一部分。在Go語言中不需要顯示地插入分號,在必要時,Go語言會自動為代碼插入分號以進行語句分隔。
Go語言代碼由若干個Unicode字符組成,Go語言的所有源代碼都必須由Unicode編碼規范的UTF-8編碼格式進行編碼(也就是說編寫的Go語言源碼文件必須是UTF-8編碼格式的)。
Go語言的標識符是由若干字母(由Unicode編碼即可)、下劃線和數字組成的字符序列;該字符序列的第一個字符必須為字母。
注意:
在Go語言代碼中,每一個標識符都必須在使用前進行聲明。
一個聲明將一個非空的標識符與一個常量、類型、變量、函數或代碼包綁定在一起。
在同一個代碼塊中,不允許重復聲明同一個標識符(除了賦值語句例外)。
在一個源碼文件和一個代碼包中的標識符都需要遵循此規則。
一個已被聲明的標識符的作用域與其直接所屬的代碼塊的范圍相同。
嚴格來講,代碼包聲明語句并不算是一個聲明。因為代碼包名稱并不會出現在任何一個作用域中。代碼包聲明語句的目的是為了鑒別若干源碼文件是否屬于同一個代碼包,或者指定導入代碼包時的默認代碼包引用名稱。
限定標識符用來訪問其他代碼包中的變量或類型。例如,當我需要訪問代碼包os中名為O_RDONLY的常量時,需要這樣寫os.O_RDONLY。
限定標識符能夠使用,需要滿足兩個前提條件:
要訪問的代碼包必須被事先導入;
這個代碼包中的標識符必須是可導出的。
一個可導出的標識符也需要滿足兩個前提條件:
標識符名稱中的第一個字符必須為大寫(Go語言根據標識符名稱中的第一個字符的大小寫來確定這個標識符的訪問權限的,當標識符名稱的第一個字符為大寫時,其訪問權限為“公開的”,也就是該標識符可以被任何代碼包中的任何代碼通過限定標識符訪問到;當標識符的第一個字符為小寫時,其訪問權限就是"包級私有的",也就是只有與該標識符同在一個代碼包的代碼才能夠訪問到它);
標識符必須是被聲明在一個代碼包中的變量或者類型的名稱,或者是屬于某個結構體類型的字段名稱或方法的名稱。
Go語言的預定義標識符:
所有基本數據類型的名稱。
接口類型error
常量true,false和iota
所有內建函數的名稱,即append、cap、close、complex、copy、delete、imag、len、make、new、panic、print、println、real和recover。
Go語言中有一個空標識符,它由一個下劃線表示,一般用于一個不需要引入一個新綁定的聲明中。例如,當我們只想執行一下某個代碼包中的初始化函數,而不需要使用這個代碼包中的任何程序實體的時候,可以編寫如下導入語句:
import _ "runtime/cgo"1.
其中,"runtime/cgo"代表了一個標準庫代碼包的標識符。
關鍵字(也稱為保留字)是被編程語言保留而不讓編程人員作為標識符使用的字符序列。
類別 | 關鍵字 |
---|---|
程序聲明 | import, 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語言并發編程。
簡單來說,字面量就是值的一種標記法。但是,在Go中,字面量的含義要更加廣泛一些。
Go語言代碼中用到的字面量有以下3類:
1、表示基礎數據類型值的各種字面量。例如,表示浮點數類型值的12E-3。
2、構造各種自定義的復合數據類型的類型字面量。例如,下面表示一個名稱為Person的自定義結構體類型:
type Person struct {
Name string
Age uint8
Address string
}
3、表示復合數據類型的值的復合字面量
被用來構造類型Struct(結構體)、Array(數組)、Slice(切片)和Map(字典)的值。例如,下面的字面量用于表示上面名稱為Person的結構體類型的值:
Person {
Name:"Huazie",
Age: "21",
Address: "Nanjing, China"
}
注意:
對復合字面量的每次求值都會導致一個新的值被創建。因此,如上該復合字面量每被求值一次就會創建一個新的Person類型的值。
Go語言不允許在一個此類的復合字面變量中,出現重復的鍵。如下都是錯誤,無法通過編譯,因為鍵都有重復。
//表示結構體類型值,有重復的鍵 Name
Person {Name: "Huazie",Age: "21", Name: "Unknown"}
//表示字典類型值,有重復的鍵 Age
map[string]string{ Name: "Huazie",Age: "21", Age: "21"}
//表示切片類型值,有重復的鍵 0
[]string{0: "0", 1: "1", 0: "-1"}
一個類型確定了一類值的集合,以及可以在這些值上施加的操作。類型可以由類型名稱或者類型字面量指定,分為基本類型和復合類型,基本類型的名稱可以代表其自身。
var bookName string1.
如上聲明了一個類型為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。如果一個類型并不屬于上述情況,那么這個類型的潛在類型就是類型聲明中的那個類型的潛在類型。
如下聲明一個自定義類型
type MyString string1.
如上可以把類型MyString看作string類型的一個別名類型,那么MyString類型的潛在類型就是string類型。Go語言基本數據類型中的rune類型可以看作是uint32類型的一個別名類型,其潛在類型就是uint32。
注意:
類型MyString和類型string是兩個不相同的類型。不能將其中一個類型的值賦給另一個類型的變量。
別名類型與它的源類型的不同僅僅體現在名稱上,它們的內部結構是一致的;下面的類型轉換的表達式都是合法的:MyString(“ABC”) 和string(MyString(“ABC”))。這種類型轉換并不會創建新的值。
一個類型的潛在類型具有可傳遞性,如下:
type iString MyString1.
則類型isString的潛在類型就是string類型。
這里聲明一個類型,如下:
type MyStrings [3]string1.
**注意:**類型MyStrings的潛在類型并不是[3]string。[3]string既不是一個預定義的類型,也不是一個由類型字面量構造的復合類型,而是一個元素類型為string的數組類型。
根據上面的定義可知類型MyStrings的潛在類型就是[3]string的潛在類型string。
Go語言規定,一個數組類型的潛在類型決定了在該類型的變量中可以存放哪一個類型的元素。
操作符就是用于執行特定算術運算或邏輯操作的符號。(這里不詳細講解了,跟C語言的操作符類似),不過Go語言中沒有三元操作符,所以除了一元操作符以外都必定是二元操作符。Go語言一共有21個操作符,包括算術操作符、比較操作符、邏輯操作符、地址操作符和接收操作符。
符號 | 說明 | 示例 |
---|---|---|
&& | 邏輯與操作。二元,邏輯操作符 | true && false //表達式結果是false |
== | 相等判斷操作。二元,比較操作符 | “abc” == “abc”//結果是true |
!= | 不等判斷操作。二元,比較操作符 | “abc” != “Abc”//結果是true |
< | 小于判斷操作。二元,比較操作符 | 1 < 2 //表達式結果是true |
<= | 小于或等于。二元,比較操作符 | 1 <= 2 //表達式結果是true |
> | 大于判斷操作。二元,比較操作符 | 3 > 2 //表達式結果是true |
>= | 大于或等于。二元,比較操作符 | 3 >= 2 //表達式結果是true |
+ | 表示求和,一元又是二元,算術操作符 | +1 //結果為1 (1+2) //結果是3 |
- | 表示求差,一元又是二元,算術操作符 | -1 //結果為-1 (1 – 2) //結果是-1 |
\ | 按位或操作,二元,算術操作符 | 5 \ 11 //表達式的結果是15 |
^ | 按位異或,一元又是二元,算術操作符 | 511//結果是14(5)//結果是-6 |
* | 求積或取值,一元,二元,算術,地址 | *p //取值操作 |
/ | 求商操作,二元,算術操作符 | 10 / 5 //表達式的結果為2 |
% | 求余數操作,二元,算術操作符 | 12 % 5 //表達式的結果為2 |
<< | 按位左移操作,二元,算術操作符 | 4 << 2 //表達式的結果為16 |
>> | 按位右移操作,二元,算術操作符 | 4 >> 2 //表達式的結果為1 |
& | 按位與操作,一元,二元,算術,地址 | &v //取地址操作 |
&^ | 按位清除操作,二元,算術操作符 | 5 &^ 11 //表達式的結果為4 |
! | 邏輯非操作,一元,邏輯操作符 | !b //若b為true,結果為false |
<- | 接收操作,一元,接收操作符 | <- ch |
注意:假設上面的ch 代表了元素類型為 byte的通道類型值,則<- ch表示從ch中接收byte類型值的操作。
重點講解3個操作符:
1、&^
實現了按位清除操作,按位清除就是根據第二個操作數的二進制值對第一個操作數的二進制值進行相應的清零操作,如果第二個操作數的某個二進制位上的數組為1,就把第一個操作數的對應二進制位上的數值設置為0。否則,第一個操作數的對應二進制位上的數值不變。這樣的操作并不會改變第一個操作數的原值,只會根據兩個操作數的二進制值計算出結果值。這樣就可以理解上面的5 &^ 11的結果為4了。
2、^
作為一元操作符,分兩種情況:
(1). 操作數是無符號的整數類型,使用這一個操作就相當于對這個操作數和其整數類型的最大值進行二元的按位異或操作,如下:
^uint8(1) = 254
//無符號整數的一元按位異或操作00000001 ^ 11111111 = 11111110//對應的二進制數運算1.2.3.
如上,內置函數uint8會將一個整數字面量轉換為一個uint8類型的值,這保證了一元操作符^的唯一操作數一定是一個無符號整數類型的值。
(2). 操作是有符號的整數類型,這一操作就相當于對這個操作數和-1進行二元按位異或操作。例如:
^1 = -2
//有符號整數的一元按位異或操作00000001 ^ 11111111 = 11111110//對應的二進制運算1.2.
**注意:**以上的操作數的二進制值都是以補碼形式表示;默認情況下整數字面量是有符號的,所以(2)中操作數1不需要顯示使用內置函數int8 。
3、<-
接收操作符,只作用于通道類型的值。使用時,需要注意兩點:
(1). 從一個通道類型的空值(即nil)接收值的表達式將會永遠被阻塞。
(2). 從一個已被關閉的通道類型值接收值會永遠成功并立即返回一個其元素類型的零值。
一個由接收操作符和通道類型的操作數所組成的表達式可以直接被用于變量賦值或初始化,如下所示(在賦值語句講解時,再細說)
v1 := <-ch
v2 = <-ch2.2.
特殊標記 = 用于將一個值賦給一個已被聲明的變量或常量。
特殊標記 := 則用于在聲明一個變量的同時對這個變量進行賦值,且只能在函數體內使用。
又如下:
v, ok = <-ch
v, ok := <-ch2.2.
當同時對兩個變量進行賦值或初始化時,第二個變量將會是一個布爾類型的值。這個值代表了接收操作的成功與否。如果這個值為false,就說明這個通道已經被關閉了。(之后講解通道類型會詳細介紹)。
優先級 | 操作符 |
---|---|
5 | * / % << >> & &^ |
4 | + - \ ^ |
3 | == != < <= > >= |
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語言允許如下的賦值語句:
v, ok := a[x]1.
如上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.(T)1.
該表達式的作用是判斷“x不為nil且存儲在其中的值是T類型的”是否成立。
如果T不是一個接口類型,那么x.(T)會判斷類型T是否為x的動態類型(一個變量的動態類型就是在運行期間存儲在其中的值的實際類型);而這個實際類型必須是該變量聲明的那個類型的一個實現類型,否則就根本不可能在該變量中存儲這一類型的值。所以類型T必須為x的類型的一個實現類型,而在Go語言中只有接口類型可以被其他類型實現,所以x的求值結果必須是一個接口類型的值。
所以上面表達式interface{}(num).(int)中表達式interface{}(num)的含義就是將變量num轉換為interface{}類型的值(即它的結果值是接口類型的),而這剛好符合前面的定義。
知識點: interface{}是一個特殊的接口類型,代表空接口。所有類型都是它的實現類型。
在對變量的賦值或初始化的時候,也可以使用類型斷言,如下:
v, ok := x.(T)1.
當使用類型斷言表達式同時對兩個變量進行賦值時,如果類型斷言成功,那么賦給第一個變量的將會是已經被轉換為T類型的表達式x的求值結果,否則賦給第一個變量的就是類型T的零值。布爾類型會被賦給變量ok,它體現了類型斷言的成功(true)與否(false)。
注意: 在這種場景下,即使類型斷言失敗也不會引發運行時恐慌。
(8) 一個基本表達式和一個調用符號組成。
調用符號只針對于函數或者方法。與調用符號組合的基本表達式不是一個代表代碼包名稱(或者其別名)的標識符就是一個代表結構體類型的方法的名稱的標識符。調用符號由一個英文句號為前綴和一個被圓括號括起來的參數列表組成,多個參數列表之間用逗號分隔。例如,基本表達式os.Open(“/etc/profile”)表示對代碼包os中的函數Open的調用。
如果函數f可以接受的參數的數量是不固定的,那么函數f就是一個能夠接受可變長參數的函數,簡稱可變參函數。在Go語言中,在可變參函數的參數列表的最后總會出現一個可變長參數,這個可變長參數的類型聲明形如…T。Go語言會在每次調用函數f的時候創建一個切片類型值,并用它來存放這些實際函數。這個切片類型值的長度就是當前調用表達式中與可變長參數綁定的實際參數的數量。
可變參函數appendIfAbsent聲明如下(函數體省略):
func appendIfAbsent(s []string, t ...string) []string1.
針對此函數的調用表達式如下:
appendIfAbsent([]string(“A”,”B”,”C”),”C”,”B”,”A”)1.
其中,與可變參數t綁定的切片類型值為[]string{”C”,”B”,”A”},包含了實際參數”C”,”B”和”A”。
也可以直接把一個元素類型為T的切片類型值賦給…T類型的可變長參數,如下調用:
appendIfAbsent([]string(“A”,”B”,”C”), []string(”C”,”B”,”A”)...)1.
或者如果有一個元素類型為stirng的切片類型的變量s的話,如下調用:
appendIfAbsent([]string(“A”,”B”,”C”), s...)1.
對于將切片類型的變量賦給可變長參數的情況,Go語言不會專門創建一個切片類型值來存儲其中的實際參數。因為,這樣的切片類型值已經存在了,可變長參數t的值就是變量s的值。
讀到這里,這篇“Go語言有哪幾類詞法元素”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。