go語言中關鍵字有25個,分別有:break(退出循環)、default(選擇結構預設項目)、func(定義函數)、interface(定義介面)、case(選擇結構標籤) 、const(定義常數)、continue、select、chan、continue(跳過本循環)、defer(延遲執行內容)、go、map、struct、else、goto、package、switch等。
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
關鍵字(也稱為保留字)是被程式語言保留而不讓程式設計人員作為標識符使用的字元序列。
關鍵字就是被Go語言賦予了特殊意義的單字,也可以稱為保留字。
Go語言中的關鍵字一共有 25 個,之所以刻意地將Go語言中的關鍵字保持的這麼少,是為了簡化在編譯過程中的程式碼解析。和其它語言一樣,關鍵字不能夠作標識符使用。
保留關鍵字 | 說明 |
---|---|
break | #退出循環 |
default | 選擇結構預設項目(switch、select) |
func | 定義函數 |
interface | 定義介面 |
#select | channel |
case | 選擇結構標籤 |
chan | #定義channel |
const | 常數 |
continue | 跳過本次循環 |
延遲執行內容(收尾工作) | |
並發執行 | |
map 類型 | |
定義結構體 | |
選擇結構 | |
跳轉語句 | |
選擇結構 | |
流程控制 | |
選擇結構 | |
從slice、map 等結構中取元素 | |
定義類型 | |
#for | 循環 |
import | #導入套件 |
return | 回傳 |
var | 定義變數 |
類別 | 關鍵字 |
---|---|
#程式聲明 | # 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語言並發程式設計。
2.1 import
import 用於導入套件,這樣就可以使用套件中被匯出的識別碼。導入格式如下:
import _ "package path" import . "package path" import alias "package path" import ( _ "package path" . "package path" alias "package path" )
其中套件路徑前面可以有三中修飾符中的某一個。底線即空白標識符,表示不使用套件中的標識符,只需要包的副作用,即計算包級變數的初始化表達式和執行導入包的init初始化函數。點號取代包的別名, 表示存取包中的匯出識別碼無需使用包名。 alias則表示包包的別名。
匯入範例如下:
导入声明 Sin的本地名 import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
#2.2 package
##package用於宣告套件的名稱,需放在go檔所有程式碼的最前面。一個套件由一個或多個go來源檔案組成,需放在同一個目錄下,且同一個目錄下的這些go檔案的package的名字只能有一個。申明格式如下:package <packagename>packagename不能為空白標識符_。
#3.1 chan
chan用來宣告channel (頻道)。通道提供一種機制使兩個並發執行的函數實現同步,並透過傳遞特定元素類型的值來通訊。未初始化的通道值為 nil。宣告格式如下:chan T // 可以被用来发送和接收类型T的值 chan<- T // 只能被用来发送浮点数 <-chan T // 只能被用来接收整数其中<-運算子指定頻道的方向,傳送或接收。若沒有給定方向,那麼該頻道就是雙向的。頻道可透過型別轉換或賦值被強制為只傳送或只接收。 通道的初始化可以透過 make 函數來實現,其結果值充當了對底層資料結構的參考。初始化時可以為頻道設定緩衝區大小,預設值為零,表示不含緩衝的或同步的頻道。
ci := make(chan int) // 整数类型的无缓冲信道 cj := make(chan int, 0) // 整数类型的无缓冲信道 cp := make(chan *os.File, 100) // 指向文件指针的带缓冲信道
3.2 const
#const 用來定義常數,一旦創建,不可賦值修改。 const可以出現在任何關鍵字var 可以出現的地方,宣告常數方式與var 宣告變數方式相同,格式如下:const name = value const name T = value const ( name = value name T = value )注意,Golang 中的const 不支援像C/ C 中修飾函數的參數和回傳值,也就是下面的語句是非法的。
func test(const name *string) func test(name *string) const *string
3.3 func
#func 用來定義函數。 Go函數支援變參且傳回值支援多個,但不支援預設參數。如果函數存在多個返回值形參則需要使用小括號括起來,定義格式如下:func funcName(){} //无参无返回值 func funcName(t T) T {} //有参有返回值 func funcName(t T, list ...T) (T1,T1) {} //有变参有多个返回值程式碼格式上需要注意的是,函數體的第一個大括號必須函數名同行。這是Go對程式碼格式的強制要求,在其它的語句中也是如此,例如if else語句、for語句、switch語句、select語句等。
3.4 interface
interface 用來定義介面。一個介面是一個方法集,如果一個類型實作了一個介面中的所有方法集,那麼說明該類型實作此介面。介面類型變數可以儲存任何實作了該介面的類型的值。特別的,interface{}表示空接口類型,預設地,所有類型都實作了空接口,所以interface{}可以接收任意類型值。範例如下://空接口 interface{} //一个简单的File接口 type File interface { Read(b Buffer) bool Write(b Buffer) bool Close() }
3.5 map##map 用於宣告映射變數。映射屬容器類別類型,是一個同種類型元素的無序組,透過唯一的鍵可以取得對應的值。可以使用 make 建立 map 變量,未初始化的映射值為 nil。建立map變數主要有以下幾種方式:
//创建0容量的map var myMap = make(map[T1] T2) //创建指定容量的map var myMap = make(map[T]T2, cap) //创建并初始化map var myMap = map[string]int { "dable" : 27, "cat" : 28, }
package main import "fmt" func main() { nameAge := make(map[string]int) nameAge["bob"] = 18 //增 nameAge["tom"] = 16 //增 delete(nameAge, "bob") //删 nameAge["tom"] = 19 //改 v := nameAge["tom"] //查 fmt.Println("v=",v) v, ok := nameAge["tom"] //查,推荐用法 if ok { fmt.Println("v=",v,"ok=",ok) } for k, v :=range nameAge { //遍历 fmt.Println(k, v) } }
v= 19 v= 19 ok= true tom 193.6 struct
struct 用來定義結構體。結構體屬容器類別類型,是多個相同或不同類型值的集合。
package main import "fmt" type Vertex struct { X, Y int } var ( v1 = Vertex{1, 2} // 类型为 Vertex v2 = Vertex{X: 1} // Y:0 被省略 v3 = Vertex{} // X:0 和 Y:0 p = &Vertex{1, 2} // 类型为 *Vertex ) func main() { fmt.Printf("%#v %#v %#v %#v\n", v1, v2, v3, p) }輸出結果:
main.Vertex{X:1, Y:2} main.Vertex{X:1, Y:0} main.Vertex{X:0, Y:0} &main.Vertex{X:1, Y:2}
3.7 type
type 用于定义类型,比如定义struct、interface与等价类型。
//定义struct type Person struct { name string } //定义接口 type Person interface { speak(word string) } //定义等价类型,rune等价于int32 type rune int32
3.8 var
var 用于定义变量,语法格式主要有:
var name T //name默认为类型T的零值 var name = value //根据值value推断变量name的类型 var name T = value //赋初始值时指明类型 var name1, name2 T //同时定义多个同类型变量 //同时定义多个不同类型的变量 var ( name string ="dable" age int = 18 )
定义变量可以使用:=来替代var,但是:=运算符只能用于函数体内。
4.1 for range break continue
(1)for 与 range for是Go中唯一用于循环结构的关键词。有三个使用方式,分别是单个循环条件,经典的初始化/条件/后续形式,还有和range关键词结合使用来遍历容器类对象(数组、切片、映射)。
//单条件 i := 1 for i <= 3 { fmt.Println(i) i = i + 1 } //初始化/条件/后续形式 //注意Go中没有前置自增与自减运算符,即++i是非法的 for i:=0; i < 3; i++ { fmt.Println(i) } //for range形式遍历数组 array :=[...]int{0,1,2,3,4,5} for i, v :=range array{ fmt.Println(i,v) }
(2)break break用于终止最内层的"for"、“switch"或"select"语句的执行。break可以携带标签,用于跳出多层。如果存在标签,则标签必须放在"for”、"switch"或"select"语句开始处。
//终止for L: for i < n { switch i { case 5: break L } }
(3)continue continue通常用于结束当前循环,提前进入下一轮循环。也可以像break一样携带标签,此时程序的执行流跳转到标签的指定位置,可用于跳出多层"for"、“switch"或"select”,提前进入下一轮的执行。示例如下:
//提前进入下一轮循环 for i:=0; i < 3; i++ { if i == 1 { continue } fmt.Println(i) } //输出结果 0 2 //提前进入标签处for的下一轮循环 L: for i:=0; i < 2; i++ { for j:=0; j < 3; j++{ if j == 1 { continue L } fmt.Println(i, j) } } //输出结果 0 0 1 0
4.2 goto
goto用于将程序的执行转移到与其标签相应的语句。可以使用goto退出多层"for"、“switch"或"select”,功能类似于break携带标签。
//终止for L: for i < n { switch i { case 5: goto L } }
注意事项: (1)执行"goto"不能在跳转过程中跳过变量的定义,不然会报编译错误。例如:
goto L //编译报错 v := 3 L: fmt.Println(v)
(2)在块外的goto语句不能跳转至该块中的标签。例如:
if n%2 == 1 { goto L1 } for n > 0 { f() n-- L1: f() n-- }
是错误的,因为标签 L1 在"for"语句的块中而 goto 则不在。 (3)程序设计时,应尽量避免使用goto语句,因为程序执行流的随意跳转会破坏结构化设计风格,导致代码可读性下降。
4.3 switch case default fallthrough
这四个关键词是结合使用的。switch语句提供多路执行,表达式或类型说明符与switch中的case相比较从而决定执行哪一分支。default用于给出默认分支,即所有的case分支都不满足时执行default分支。Go中的switch语句在执行完某个case子句后,不会再顺序地执行后面的case子句,而是结束当前switch语句。使用fallthrough可以继续执行后面的case与default子句。
下面分别以表达式选择或类型选择为例演示switch case default fallthrough的用法。
//表达式选择 switch tag { default: s3() //default子句可以出现在switch语句中的任意位置,不一定是最后一个 case 0, 1, 2, 3: s1() //case表达式可以提供多个待匹配的值,使用逗号分隔 case 4, 5, 6, 7: s2() } switch x := f(); { case x < 0: return -x //case表达式无需为常量 default: return x } switch { //缺失的switch表达式意为"true" case x < y: f1() fallthrough //强制执行下一个case子句 case x < z: f2() //此处没有fallthrough,switch执行流在此终止 case x == 4: f3() } //类型选择 switch i := x.(type) { case int: printInt(i) // i 的类型为 int case float64: printFloat64(i) // i 的类型为 float64 case func(int) float64: printFunction(i) // i 的类型为 func(int) float64 case bool, string: printString("type is bool or string") // i 的类型为 bool or string default: printString("don't know the type") // i 的类型未知 }
4.4 if else
if与else实现条件控制,与C有许多相似之处,但也有其不同之处。变化主要有三点: (1)可省略条件表达式的括号; (2)支持初始化语句,可定义代码块局部变量; (3)if与else块中只有一条语句也需要添加大括号; (4)起始大括号必须与if与else同行。
if err := file.Chmod(0664); err != nil { log.Print(err) return err }
4.5 return defer
(1)return return用于函数执行的终止并可选地提供一个或多个返回值。 任何在函数F中被推迟的函数会在F 返回给其调用者前执行。函数可以通过return返回多个值。如果返回值在函数返回形参中指定了名字,那么return时可不带返回值列表。
//无返回值 func noResult() { return } //单返回值 func simpleF() int { return 2 } //多返回值 func complexF2() (float64, float64) { re = 7.0 im = 4.0 return re, im } //返回值已具名 unc complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return }
(2)defer defer语句用于预设一个函数调用,即推迟函数的执行。 该函数会在执行 defer 的函数返回之前立即执行。它显得非比寻常, 但却是处理一些事情的有效方式,例如无论以何种路径返回,都必须释放资源的函数。 典型的例子就是解锁互斥和关闭文件。
//将文件的内容作为字符串返回。 func Contents(filename string) (string, error) { f, err := os.Open(filename) if err != nil { return "", err } defer f.Close() // f.Close 会在函数结束后运行 var result []byte buf := make([]byte, 100) for { n, err := f.Read(buf[0:]) result = append(result, buf[0:n]...) if err != nil { if err == io.EOF { break } return "", err // 我们在这里返回后,f 就会被关闭 } } return string(result), nil // 我们在这里返回后,f 就会被关闭 }
推迟诸如 Close 之类的函数调用有两点好处:第一, 它能确保你不会忘记关闭文件。如果你以后又为该函数添加了新的返回路径时, 这种情况往往就会发生。第二,它意味着“关闭”离“打开”很近, 这总比将它放在函数结尾处要清晰明了。
使用defer时,需要注意两点: (a)被推迟函数的实参(如果该函数为方法则还包括接收者)在推迟执行时就会求值,而不是在调用执行时才求值。这样不仅无需担心变量值在函数执行时被改变, 同时还意味着可以给被推迟的函数传递不同参数。下面是个简单的例子。
for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) }
(b)被推迟的函数按照后进先出(LIFO)的顺序执行,因此以上代码在函数返回时会打印 4 3 2 1 0。
4.6 go
go用于创建Go程(goroutine),实现并发编程。Go程是与其它Go程并发运行在同一地址空间的函数,相比于线程与进程,它是轻量级的。Go程在多线程操作系统上可实现多路复用,因此若一个线程阻塞,比如说等待I/O,那么其它的线程就会运行。Go程的设计隐藏了线程创建和管理的诸多复杂性。
在函数或方法前添加 go 关键字能够在新的Go程中调用它。当调用完成后,该Go程也会安静地退出。效果有点像Unix Shell中的 & 符号,它能让命令在后台运行。
package main import ( "fmt" "time" ) func main() { go func(){ fmt.Println("in first goroutine") }() go func(){ fmt.Println("in second goroutine") }() fmt.Println("main thread start sleep, and other goroutine start execute") time.Sleep(10*time.Second) }
输出结果:
main thread start sleep, and other goroutine start execute in second goroutine in first goroutine
注意,从输出结果可以看出,go程的执行顺序和创建的顺序是没有关系的,也就是说存在多个go程时,其执行的顺序是随机的。
4.7 select
select语句用来选择哪个case中的发送或接收操作可以被立即执行。它类似于switch语句,但是它的case涉及channel有关的I/O操作。也就是说select就是用来监听和channel有关的IO操作,它与select, poll, epoll相似,当IO操作发生时,触发相应的动作,实现IO多路复用。
package main import "fmt" func main(){ ch1 := make(chan int, 1) ch2 := make(chan int, 1) ch1 <- 3 ch2 <- 5 select { case <- ch1: fmt.Println("ch1 selected.") case <- ch2: fmt.Println("ch2 selected.") default: //如果ch1与ch2没有数据到来,则进入default处理流程。如果没有default子句,则select一直阻塞等待ch1与ch2的数据到来 fmt.Println("default") } }
输出结果:
ch1 selected. //或者 ch2 selected.
从输出结果可以看出,当存在多个case满足条件,即有多个channel存在数据时,会随机的选择一个执行。
以上是go語言中關鍵字有多少個的詳細內容。更多資訊請關注PHP中文網其他相關文章!