入門教程:花 5 分鐘學習 Go 語言
這是一篇外文,號稱五分鐘入門 Go 語言。在周刊中推薦了這篇文章,今天看到 Seekload 翻譯了,推薦給新手!
via:
https://gist.github.com/prologic/5f6afe9c1b98016ca278f4d507e65510
作者:prologic
四哥水平有限,如有翻譯或理解錯誤,煩請幫忙指出,感謝!
上周五的分享預告點贊已破百,成功解鎖了今天的文章。
前幾天看到優(yōu)質文章推送,注意到這篇文章(主要是標題吸引了我),文章非常簡潔,讓我們一起來回顧下相關的基礎知識。
原文如下:
基本
作為經典的 “Hello World”,你的第一個 Go 程序非常簡單:
先為我們的項目創(chuàng)建 workspace:
$?mkdir?hello
$?cd?hello
接著創(chuàng)建并初始化 Go module:
$?go?mod?init?hello
使用你最喜歡的編輯器創(chuàng)建 main.go 文件,輸入如下代碼,并將文件保存在上面創(chuàng)建的 hello 目錄下。
package?main
import?"fmt"
func?main()?{
??fmt.Println("Hello?World!")
}
最后編譯產生一個二進制文件:
$?go?build
在 workspace 下會生成一個名為 hello 的二進制可執(zhí)行文件,運行它會輸出:
$?./hello
Hello?World!
變量
在 Go 語言里,你可以使用下面兩種方法創(chuàng)建變量:
var?x?int
其他類型,包括 int、int32、int64、float32、float64、bool和 string 等,還有帶 u 前綴的無符號整型類型,例如:uint8 與 byte 是同一種類型(ps:可以認為 type 是 uint8 的別稱,見源碼 type byte = uint8)
或者創(chuàng)建變量時直接賦值,Go 編譯器能自動推導變量類型:
x?:=?42
通過操作符 = 賦值:
x?=?1
注意: 大部分時候你都不需要使用 var 關鍵字,除非創(chuàng)建變量之后再賦值或者需要使用變量的零值。
函數
使用關鍵字 func 聲明函數:
func?hello(name?string)?string?{
??return?fmt.Sprintf("Hello?%s",?name)
}
函數如果有返回值,必須顯示地指明返回值類型。
函數可以有多個返回值(一般返回錯誤和值):
func?isEven(n?int)?(bool,?error)?{
??if?n?<=?0?{
????return?false,?fmt.Errorf("error:?n?must?be?>?0")
??}
??return?n?%?2?==?0,?nil
}
函數是 Go 語言的“一等公民”,因此支持很多函數式編程的很多特性,包括閉包、將函數作為參數傳遞或者返回等,例如:
func?AddN(n?int)?func(x?int)?int?{
??return?func(x?int)?int?{
????return?x?+?n
??}
}
結構體
由于 Go 是一種多范式語言,因此它還通過結構體實現“面向對象”編程,使用關鍵字 struct 定義結構體:
type?Account?struct?{
??Id??????int
??Balance?float64
}
結構體字段的定義與變量定義類似,使用操作符 . 訪問字段:
account?:=?Account{}
fmt.Printf("Balance:?$%0.2f",?account.Balance)
方法
結構體可以擁有自己的方法。不像其他語言,Go 語言不支持繼承也沒有類(我們可以通過結構體嵌套實現“繼承”)。
type?Account?struct?{
??id??int
??bal?float64
}
func?(a?*Account)?String()?string?{
??return?fmt.Sprintf("Account[%d]:?$0.2f",?a.id,?a.bal)
}
func?(a?*Account)?Deposit(amt?flaot64)?float64?{
??a.bal?+=?amt
??return?a.bal
}
func?(a?*Account)?Withdraw(amt?float64)?float64?{
??a.bal?-=?amt
??return?a.bal
}
func?(a?*Account)?Balance()?float64?{
??return?a.bal
}
這些方法稱為指針接收者方法,因為第一個參數是指向 Account 結構體的指針。
你還可以像下面這樣定義方法:
type?Circle?struct?{
??Radius?float64
}
func?(c?Circle)?Area()?float64?{
??return?3.14?*?c.Radius?*?c.Radius
}
剛剛定義的是值接收者方法,在方法中對結構體修改不會影響到原結構體,是一份拷貝。
關于結構體、指針接收者方法和值接收者方法可以查看文末推薦閱讀了解更多。
數組和 Slice
與其他語言類似,Go 支持數組,不同的是 Go 語言數組是固定長度的(聲明長度之后不支持動態(tài)變化),與 C 語言數組類似。
可以指定大小和類型創(chuàng)建數組:
xs?:=?[4]int{1,?2,?3,?4}
大多數場景你會更喜歡使用 slice,有點類似其他語言(比如 Python)中的 list,支持自動擴容。
創(chuàng)建 slice 時可以不用指定大小:
xs?:=?[]int{1,?2,?3,?4}
slice 也可以通過 append() 函數創(chuàng)建:
xs?:=?[]int{}
xs?=?append(xs,?1)
xs?=?append(xs,?2)
xs?=?append(xs,?3)
可以通過索引范圍 slice:
xs[1]??//?2
你還可以通過“切片”操作獲取數組或者 slice 的子集:
ys?:=?xs[1:]?//?[2,?3]
可以使用 range 關鍵字迭代 數組或者 slice:
for?i,?x?:=?range?xs?{
??fmt.Printf("xs[%d]?=?%d\n",?i,?x)
}
map
Go 語言里存儲鍵值對的內置數據結構稱為 map(類似其他語言的 hash table、hash map、字典或者關聯數組)。
可以通過關鍵字 map 創(chuàng)建 map,需要分別定義鍵值的類型,比如定義鍵類型為 string、值類型為 int 的 map:
var?counts?map[string]int
也可以像下面這樣創(chuàng)建 map:
counts?:=?map[string]int{
??"Apples":?4,
??"Oranges":?7,
}
類似數組和 slice,也可以通過鍵訪問值:
counts["Apples"]??//?4
像數組和 slice 一樣,迭代 map:
for?key,?value?:=?range?counts?{
??fmt.Printf("%s:?%d\n",?key,?value)
}
唯一需要注意的是,map 使用之前需要先初始化,操作 nil map 將會導致 error 和 panic:
var?counts?map[string]int
counts["Apples"]?=?7??//?This?will?cause?an?error?and?panic!
使用之前必須使用 make() 函數初始化:
counts?:=?make(map[string]int)
counts["Apples"]?=?7
關于數組、slice 和 map 更詳細的用法可以查看文末推薦閱讀掌握。
流控制
for
Go 語言里面只有一種循環(huán)結構,在之前的章節(jié)里或許你也看到了:
sum?:=?0
for?i?:=?0;?i?10;?i++?{
??sum?+=?i
}
for 循環(huán)語句由三部分組成:
初始化語句:第一次迭代之前執(zhí)行;
條件表達式:每次迭代之前都會執(zhí)行;
post 語句:每次迭代之后都會執(zhí)行;
如果忽略循環(huán)條件,得到的是無限循環(huán):
for?{
}
//?This?line?is?never?reached!
if-else
Go 語言支持 if-else 語句:
N?:=?42
func?Guess(n?int)?string?{
??if?n?==?42?{
????return?"You?got?it!"
??}?else?if?n?????return?"Too?low!?Try?again..."
??}?else?{
????return?"Too?high!?Try?again..."
??}
}????????
注意:可以忽略最后一個 else,直接像這樣返回 return "Too high~ Try again…",兩者是等價的。
switch
Go 語言提供的 switch 語句可以代替 if-else,比如:
func?FizzBuzz(n?int)?string?{
??switch?n?{
??case?n?%?15?==?0:
????return?"FizzBuzz"
??case?n?%?3?==?0:
????return?"Fizz"
??case?n?%?5?==?0:
????return?"Buzz"
??default:
????return?fmt.Sprintf("%d",?n)
??}
}
defer
關鍵字 defer 可以定義延遲函數,在調用函數返回之前調用,通常在調用函數執(zhí)行結束之前自動關閉資源(比如文件句柄、數據庫連接等),像下面這樣:
package?main
import?(
??"os"
??"fmt"
)
func?Goodbye(name?string)?{
??fmt.Printf("Goodbye?%s",?name)
}
func?Hello(name?string)?{
??defer?Goodbye(name)
??fmt.Printf("Hello?%s",?name)
}
func?main()?{
??user?:=?os.Getenv("User")
??Hello(user)
}
執(zhí)行會輸出:
$?./hello
Hello?prologic
Goodbye?prologic
關于?defer 語句的詳細使用方法可以閱讀文末推薦閱讀掌握。
錯誤處理
Go 語言里 Errors 代表的是值,比如,使用 os.Open 打開一個文件,如果成功的話會返回一個指向文件的指針和 nil;否則返回 nil 指針和具體的錯誤。
f,?err?:=?os.Open("/path/to/file")
類似其他值類型一樣檢查錯誤:
f,?err?:=?os.Open("/path/to/file")
if?err?==?nil?{
??//?do?something?with?f
}
Go 語言里,通常的做法是檢查函數是否返回非 nil 錯誤,是的話就直接返回,比如:
func?AppendFile(fn,?text?string)?error?{
??f,?err?:=?os.OpenFile(fn,?os.O_CREATE|os.O_APPEND|os.WR_ONLY,?0644)
??if?err?!=?nil?{
????return?fmt.Errorf("error?opening?file?for?writing:?%w",?err)
??}
??defer?f.Close()
??if?_,?err?:=?f.Write([]byte(text));?err?!=?nil?{
????return?fmt.Errorf("error?writing?text?to?fiel:?%w",?err)
??}
??return?nil
}
創(chuàng)建和導入包
Go 支持 module(包管理),允許你創(chuàng)建并導入相關包,在剛開始的基本章節(jié)中,我們已經知道如何在啟動新項目時使用 go mod init 創(chuàng)建模塊。
Go 的包僅僅是一個包含源代碼目錄:
創(chuàng)建 Go 包的第一步是創(chuàng)建一個目錄,就像下面這樣:
$?mkdir?shapes
使用命令 go mod init 初始化:
$?cd?shapes
$?go?mod?init?github.com/prologic/shapes
現在讓我們一起使用你最喜歡的編輯器創(chuàng)建一個 circle.go 模塊:
package?shapes
type?Circle?struct?{
??Radius?float64
}
func?(c?Circle)?String()?string?{
??return?fmt.Sprintf("Circle(%0.2f)",?c.Radius)
}
func?(c?Circle)?Area()?float64?{
??return?3.14?*?c.Radius?*?c.Radius
}
需要特別注意的是,包里的函數、結構體、變量和常量的首字母必須是大寫才是可導出的;否則即使你導入了相關包也無法訪問。
現在,在 Git 上創(chuàng)建名為 shapes 的倉庫并 push 你的包代碼:
$?git?init
$?git?commit?-a?-m?"Initial?Commit"
[email protected]:prologic/shapes.git
$?git?push?-u?origin?master
這樣的話,你就可以使用全路徑 github.com/prologic/shapes 導入 shapes 包,編譯時會根據路徑自動拉取并構建包。
例如:
我們使用 github.com/prologic/shapes 包做一個例子:
$?mkdir?hello
$?go?mod?init?hello
編寫 main.go:
package?main
import?(
??"fmt"
??"github.com/prologic/shapes"
)
func?main()?{
??c?:=?shapes.Circle{Radius:?5}
??fmt.Printf("Area?of?%s:?%0.2f\n",?c,?c.Area())
}
編譯:
$?go?build
運行二進制文件:
$?./hello
Area?of?Circle(5.00):?78.50
Congratulations!
Now you're a Gopher!
ps: 看原文評論,作者反饋接下來還會繼續(xù)更新原文,我們拭目以待,如果更新的話第一時間給大家分享。
推薦閱讀
