Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Golang 入門初體驗
學習主題
• 社群成立目的簡介
• 自我介紹與哈啦
• 功力複習
• 程式實作(Golang)
• 問題與交流
個人簡介
諸葛魔斌
工作室:諸葛魔斌科技創作室
學歷:高應大---工管系(非資訊科系)
E-Mail:chugermobin@gmail.com
官方網站:http://twcts.com
Facebook:https://goo.gl/vol...
學習程式的歷程
學生時期:打電動,沒有日夜的界限
二專畢業:初次接觸 dBase、Lotus  使用 Clipper 做經銷存、應收付帳系統
工作階段1:接觸 Office,開始使用Excel(Lotus)
工作階段2:品保工作,自學圖表、函...
Golang 入門初體驗
Go,又稱golang,是Google開發的一種靜態強型別、編譯型,並發型,並具有垃圾回收功能的程
式語言。
羅伯特·格瑞史莫,羅勃·派克(Rob Pike)及肯·湯普遜於2007年9月開始設計Go語言,稍後Ian
L...
Golang 入門初體驗
當前有兩個Go語言的編譯器的分支。官方編譯器gc和gccgo。官方編譯器在初期使用C寫成,後用go
重寫從而實作自舉。Gccgo是一個使用標準GCC作為後端的Go編譯器。
官方編譯器支援跨平台編譯(但不支援CGO),允...
Golang 入門初體驗
goroutine
這是Go的最大特色之一, thread 的使用是非常消耗系統資源的, 而且當你使用越來越多時管理上也越
困難. 而 goroutine 有輕巧低消耗資源的特性, 而這優點在於系統資源的消耗也會比較少...
Golang 入門初體驗
Go 安裝
http://golang.org/dl/
Windows:
安裝好 GO 後, 還需要 GCC 編譯環境, 因為 Mac 的 Xcode 本身就有 GCC, windows 沒有, 所以
選擇了 ming...
Golang 入門初體驗
Go 執行
https://golang.org/cmd/go/
go run
要撰寫第一個 Hello, World 程式,你可以建立一個 main.go,在當中撰寫以下的內容:
package main
impor...
Golang 入門初體驗
Go 執行
每個 .go 原始碼,都必須從 package 定義開始,而對於包括程式進入點 main 函式的 .go 原始碼,
必須是在 package main 之中,為了要能輸出訊息,這邊使用了 fmt 套件(pa...
Golang 入門初體驗
Go 執行
那麼,一開始的 package 是怎麼回事?試著先來建立一個 hello.go:
package hello
import "fmt"
func HelloWorld() {
fmt.Println("He...
Golang 入門初體驗
Go 執行
記得,package 中定義的函式,名稱必須是以大寫開頭,其他套件外的程式,才能進行呼叫,若
函式名稱是小寫,那麼會是套件中才可以使用的函式。
接著,原本的 main.go 修改為:
package mai...
Golang 入門初體驗
Go 執行
現在顯然地,main.go 中要用到方才建立的 hello 套件中的 HelloWorld 函式,這時 package 的
設定就會發揮一下效用,你得將 hello.go 移到 src/hello 目錄之中...
Golang 入門初體驗
Go 執行
go build
這個命令主要用於測試編譯。在包的編譯過程中,在必要情況下,還可以同時編譯與之關聯的包。
-普通包:執行完go build ,不會產生任何檔,如果需要在$GOPATH/pkg下生成相應檔,則...
Golang 入門初體驗
Go 執行
go build
go build 會忽略目錄下以"_"或"."開頭的go文件
如果原始程式碼針對不同的作業系統需要不同的處理,那麼可以根據不同的作業系統尾碼來命名檔。
例如,readfile_linux....
Golang 入門初體驗
Go 執行
go build
如果想編譯原始碼為可執行檔,那麼可以使用 go build,例如,直接 go build main.go,就會在
執行指令的目錄下,產生一個名稱為 main 的可執行檔,可執行檔的名稱是來...
Golang 入門初體驗
Go 執行
go build
~go
|~bin/
| |-main
|~pkg/
| `~linux_arm/
| `-hello.a
|~src/
| |~hello/
| | `-hello.go
| |~mai...
Golang 入門初體驗
Go 執行
go build
可以使用 go env 來查看 Go 使用到的環境變數,例如:
$ go env
GOARCH="arm"
GOBIN=""
GOEXE=""
GOHOSTARCH="arm"
GOHOS...
Golang 入門初體驗
Go 執行
go build
.a 檔案是編譯過後的套件,因此,你看到的 hello.a,就是 hello.go 編譯之後的結果,如果編譯
時需要某個套件,而對應的 .a 檔案存在,且原始碼自上次編譯後未曾經過修改,那...
Golang 入門初體驗
Go 執行
os.Args
那麼,如果想在執行 Go 程式時使用命令列引數呢?可以使用 os 套件的 Args,例如,寫一個
main.go:
package main
import "os"
import "fmt"...
Golang 入門初體驗
Go 執行
os.Args 是個陣列,索引從 0 開始,索引 0 會是編譯後的可執行檔名稱,索引 1 開始會是你提供
的引數,例如,在執行過 go build 或 go install 之後,如下直接執行編譯出來的執行...
Golang 入門初體驗
Go 執行
fmt 的 Printf,就像是 C 的 printf,可用的格式控制字元可參考 Package fmt 的說明。實際上,
Go 本身附帶了說明文件,可以執行 go doc <pkg> <sym>[.<me...
Golang 入門初體驗
Go 執行
go fmt
幫助格式化寫好的代碼檔,讓寫代碼時不關心格式,寫完後,輕鬆執行go fmt 檔案名.go就好
提高效率。更多的時候可以採用gofmt,同時增加-w的參數,否則格式化結果不會寫入檔,例如:
go...
Golang 入門初體驗
Go 執行
go doc
如何查看相應的package文檔呢?
如果是builtin包,可以執行go doc builtin;如果是http包,執行go doc net/http;
查看某個包裡面的函數,類似執行 go...
Golang 入門初體驗
Go IDEs
IDEs 有以下幾種,使用文字編輯器亦可完成程式編輯,再至Command Line執行編譯
Lite IDE
GoSublime
Visual Studio Code
Goclipse
VIM / VI...
Golang 入門初體驗
Go 語法 (參考 https://polor10101.gitbooks.io/golang_note/content/about_golang.html)
variable 變數
雖然號稱和 c 類似, 不過 go...
Golang 入門初體驗
Go 語法
函式
函式的宣告方式也和 c 不同
func add( a int , b int){
c := a + b
}
如果要回傳東西
func add( a int , b int) int{
c := a +...
Golang 入門初體驗
Go 語法
函式
你也可以
func add( a int , b int) int{ }
但是不可以採用對齊的方式
func add( a int , b int) int
{
}
從以上例子來看, 會發現 go 在...
Golang 入門初體驗
Go 語法
函式
有幾點初學的時候有點不習慣
每行 code 不需要分號 ;
大括號的排版方式
import 某個 lib 或是宣告某變數但是實際卻沒有使用
宣告改成這個方式, 官方是說可以增加閱讀性. why? 這部...
Golang 入門初體驗
Go 語法
關於語法
go 在語法中做了改變, 官方的說法是, 改這樣的原因是因為這樣比較好閱讀. 接著來比較 c 和 go 的語法
以宣告 variable 來看
int add; //c
var add int /...
Golang 入門初體驗
Go 語法
關於語法
如果宣告一個 function pointer 然後輸入一個 function pointer 變數
int (*fp)(int (*ff)(int x, int y), int b) //c
f...
Golang 入門初體驗
Go 語法
loop 迴圈
以 c 來說迴圈有 for , while , do while 三個關鍵字. 在 go 裡面只有一個 for 來達到全部
以 for 迴圈來說 c 為
int i = 0;
int sum...
Golang 入門初體驗
Go 語法
loop 迴圈
c 的 do while 迴圈
int i = 0;
do{
i += 1
}while( i < 10 );
go 中為
i := 0
for i < 100 {
i += 1
}
c 的...
Golang 入門初體驗
Go 語法
if switch
和 c 不同的是, if 不需要小括號, 另外大括號必須要有, 並且強制是範例的排版方式, 否則會有 error
if a > 0 {
fmt.Println(a)
}
個人是習慣對齊的...
Golang 入門初體驗
Go 語法
Array
array 的宣告
var a [5]int //宣告一個大小5的 int array
var b []int //宣告空的 int array
var c = []int{1,2,3,4,5}...
Golang 入門初體驗
Go 語法
Array
初始話也可以改成
var a = [4]int {
1,
2,
3,
4,
}
其中 4 的後面記得要有逗號 ','
Golang 入門初體驗
Go 語法
Slice
相對於 array, slice 提供了彈性, 不需要指定大小
是由三個元件組成
ptr
len
cap
其中 prt 是指向一個 array 的指標, 如圖所示
Golang 入門初體驗
Go 語法
Slice
len 為實際資料長度, cap 表示容量
宣告的方式為
a := []int
此時的 len , cap 都為 0
你可以用 make 來宣告變數並指定 len 和 cap 的值
a := m...
Golang 入門初體驗
Go 語法
Slice
也可以不指定 cap 寫成
a := make([]int,5)
這時 len 為 5 , cap 為 5
另外給定初始值的宣告
var a = []int {1,2,3,4,5}
如果要一個變...
Golang 入門初體驗
Go 語法
Slice
其中
b 為 3 , 4.
a[2:4] 的 2 表示指向 a index = 2 的位置, 4 表示為結尾在 index = 4(不包含), 所以則 length 為 2, 另外由於
arra...
Golang 入門初體驗
Go 語法
Slice
所以可以得知
a[:3] 和 a[1:] 個別為
1,2,3 //a[:3]
2,3,4,5 //a[1:]
另外要特別注意的是,
b := a[1:3]
並不是 a copy 值給 b, 而是...
Golang 入門初體驗
Go 語法
Slice
這是把 c 的前兩個的值, copy 到 b 中. 為什麼只 copy c 的前兩個?因為 b 的大小只有二, 以小的為主
copy(c,b)
則表示將 b 的值, copy 覆蓋 c 的前兩個...
Golang 入門初體驗
Go 語法
Map
建立一個 map 可以用以下兩種方式
m := make(map[string]int)
m := map[string]int{}
定義 age = 16
m["age"] = 16
回傳值, 和...
Golang 入門初體驗
Go 語法
Map
利用 rage 取得 map 中所有的 key 和 value, 並列印
for key, value := range m {
fmt.Println("Key:", key, "Value:",...
Golang 入門初體驗
Go 語法
Goroutine
在講goroutine之前, 必須先了解 concurrency 和 parllelism的不同
concurrency (併發) vs parallelism (並行)
併發 conc...
Golang 入門初體驗
Go 語法
Goroutine
Golang 入門初體驗
Go 語法
Goroutine
並行 parallelism 是多個 process 由多個 cpu 去執行, 可以增加執行的效率, 縮短總執行的時間. 如圖二所示
Golang 入門初體驗
Go 語法
Goroutine
go 用 goroutine 實現了 concurrency. 使用者只要設定最大的 thread 數量, 和系統是多少CPU, run-time 就會
幫你處理好剩下的 thread ...
Golang 入門初體驗
Go 語法
Goroutine
第一. 在創造 goroutine 的資源消耗是很小的, 因為 goroutine 只是一個 function 的入口. 只要很小的 stack 去
記錄即可.
第二. thread 上...
Golang 入門初體驗
Go 語法
goroutine - channels
Don't communicate by sharing memory; share memory by communicating.
不同於過去的 muliti ...
Golang 入門初體驗
Go 語法
goroutine - channels
但是 code 無法跑, compiler 會顯示 dead lock.
因為執行到 s <- "hello" 這步的時候, sender 就會進入 ready 狀...
Golang 入門初體驗
Go 語法
goroutine - channels
執行順序就是
1. 建立一個 goroutine //此時 s <- "hello" 還沒執行
2. 執行 val := <- s //s 空的, receiver...
Golang 入門初體驗
Go 語法
goroutine – channels
import "fmt"
func main(){
s := make(chan string)
go func() {
for i := 0; i < 3; i+...
Golang 入門初體驗
Go 語法
goroutine – channels
結果
sender hello 0
sender hello 1
receiver hello 0
receiver hello 1
sender hello 2
...
Golang 入門初體驗
Go 語法
goroutine – channels
另外我們可以修改 channel 的大小為 2
import "fmt"
func main(){
s := make(chan string,2)
go func...
Golang 入門初體驗
Go 語法
defer panic recover
defer
先看以下範例
func f(){
for i := 0 ; i < 5 ; i++{
fmt.Println(i)
}
fmt.Println("f fi...
Golang 入門初體驗
Go 語法
defer panic recover
如果再 fmt.Println 前面加上 defer
func f(){
for i := 0 ; i < 5 ; i++{
defer fmt.Println(i)...
Golang 入門初體驗
Go 語法
defer panic recover
defer 是讓 fmt.Println(0) , fmt.Println(1) , fmt.Println(2) , fmt.Println(3) , fmt.Pr...
Golang 入門初體驗
Go 語法
defer panic recover
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os....
Golang 入門初體驗
Go 語法
defer panic recover
這個例子有個 bug, 就是當 os.Create(dstName) 失敗的時候 function 就會 return, 而 src.Close() 就沒有執行
到了...
Golang 入門初體驗
Go 語法
defer panic recover
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os....
Golang 入門初體驗
Go 語法
defer panic recover
但是如果開多個檔案? 那會很麻煩
所以我們利用 defer 來修改
func CopyFile(dstName, srcName string) (written i...
Golang 入門初體驗
Go 語法
defer panic recover
但是如果開多個檔案? 那會很麻煩
所以我們利用 defer 來修改
func CopyFile(dstName, srcName string) (written i...
Golang 入門初體驗
Go 後續
GoWeb
Go Bot (Line、Facebook Message、Slack、Telegram、 ……..)
Go 機器學習
Go 物聯網
Golang 入門初體驗
Upcoming SlideShare
Loading in …5
×

Golang 入門初體驗

1,169 views

Published on

Golang 的效能可以跟C++相比,多數Bot也是用Golang寫的,甚至物聯網也不放過,可見Golang有神奇的地方,到底有多「神奇」,歡迎一起來探索吧!

Published in: Education
  • Be the first to comment

Golang 入門初體驗

  1. 1. Golang 入門初體驗
  2. 2. 學習主題 • 社群成立目的簡介 • 自我介紹與哈啦 • 功力複習 • 程式實作(Golang) • 問題與交流
  3. 3. 個人簡介 諸葛魔斌 工作室:諸葛魔斌科技創作室 學歷:高應大---工管系(非資訊科系) E-Mail:chugermobin@gmail.com 官方網站:http://twcts.com Facebook:https://goo.gl/volM7Z 粉絲團 :https://goo.gl/LI08wh 社群 :https://goo.gl/kjCsz1 Line (id) :http://goo.gl/ayGW7d Line@ :http://goo.gl/pQHjWH Line Bot :http://goo.gl/ljdxfV Play商店:http://goo.gl/CkVdsd App Store:http://apple.co/1Qehd64 專長:VB(VBA)、C#、Java(Android)、Swift(iOS)、PHP、Python、Conrona、 Golang、Unity、MySQL、FreeBSD、Server架設、CAD 、 …… 楊政斌
  4. 4. 學習程式的歷程 學生時期:打電動,沒有日夜的界限 二專畢業:初次接觸 dBase、Lotus  使用 Clipper 做經銷存、應收付帳系統 工作階段1:接觸 Office,開始使用Excel(Lotus) 工作階段2:品保工作,自學圖表、函數、VBA,做出自動化品管系統 興趣展開:自學VB,製作ERP系統,接觸Linux、FreeBSD,自學架設Server  諸葛魔斌誕生 大學時期:半自學 Android App(Java)、C#、iOS App(Swift) 工作轉變:成立諸葛魔斌科技創作室,接案學習,救國團電腦資訊講師 實績:
  5. 5. Golang 入門初體驗 Go,又稱golang,是Google開發的一種靜態強型別、編譯型,並發型,並具有垃圾回收功能的程 式語言。 羅伯特·格瑞史莫,羅勃·派克(Rob Pike)及肯·湯普遜於2007年9月開始設計Go語言,稍後Ian Lance Taylor, Russ Cox加入專案中。Go語言是基於Inferno作業系統所開發的。Go語言於2009 年11月正式宣布推出,成為開放原始碼專案,並在Linux及Mac OS X平台上進行了實現,後追加 Windows系統下的實作。 Go語言的語法接近C語言,但是對於變數的聲明是不同的,其他語法不同之處是For迴圈和if判斷語 句不需要用小括弧括起來。Go語言支援垃圾回收功能。Go語言的並列模型是以東尼·霍爾的交談循 序程式(CSP)為基礎,採取類似模型的其他語言套件括Occam和Limbo,但它也具有Pi運算的特 徵,比如通道傳輸。 與C++相比,Go語言並不包括如例外處理、繼承、泛型、斷言、虛擬函式等功能,但增加了slice型、 並行、管道、垃圾回收、介面(interface)等特性的語言級支援。當然,Google對於泛型的態度 還是很開放的,但在該語言的常見問題列表中,對於斷言的存在,則持負面態度,同時也為自己不 提供型別繼承來辯護。不同於Java,Go語言內嵌了關聯陣列(也稱為雜湊表(hashes)或字典 (dictionaries)),就像字串類型一樣。
  6. 6. Golang 入門初體驗 當前有兩個Go語言的編譯器的分支。官方編譯器gc和gccgo。官方編譯器在初期使用C寫成,後用go 重寫從而實作自舉。Gccgo是一個使用標準GCC作為後端的Go編譯器。 官方編譯器支援跨平台編譯(但不支援CGO),允許將源碼編譯為可在目標系統、架構上執行的二進 位檔案。 Go 在2007年9月開始為 google 內部員工的 20% 自由時間的實驗項目, 目的為改善公司內部的開發速 度. 隔了一年受到 google 公司的重視和支持, 2009年11 月對外發佈第一版本. 過去 google 常用的語 言有 c , java , python來開發他們的服務. 但是這些語言是在創造的時候的硬體環境, 和現在有很大的 不同. 而 Golang 在設計的時候就考慮了這些架構, 所以在開發上和過去的語言比較起來有很大的優勢. Go的關鍵字不多(目前約25個 c 37個,c++ 84個而且還在增加中), 學習上很容易上手, 再加上有不少和 c 的關鍵字重複, 所以如果你原本就是寫c/c++的人, 在轉換上會相對其他語言容易. 平均下來效能是輸c, 可是贏其他語言如 ruby(ror), php, java, python等語言. 主要原因的先天優勢是, 他語言架構設計非常單純, 並不像是如物件導向語言這麼的大. 再來是他不是直譯語言. 光是這兩點優 勢, 讓他有更好的體質去有較好的執行效率. 已經有很多案例, 在開發伺服器的軟體時, 因為效能問題而 改換 go 去寫, 結果讓他們減少了伺服器的數量就可以達到原本的效能, 增加了服務的效率也省下了硬 體成本.
  7. 7. Golang 入門初體驗 goroutine 這是Go的最大特色之一, thread 的使用是非常消耗系統資源的, 而且當你使用越來越多時管理上也越 困難. 而 goroutine 有輕巧低消耗資源的特性, 而這優點在於系統資源的消耗也會比較少. 可以使用 c library 他可以使用 c library, 解決新語言在 library 上的不足. 不過基本上 go 本身的 lib 已經很豐富了. Unicode slice map 都有支援. 目前越來越多公司用 go 來寫他們網站後端的系統, 過去 google 在寫他的服務大多使用 c + python, python 是個很簡潔的語言在建構服務是非常快的, c 是用來解決效能上的問題, 現在內部也都慢慢轉成 go 來寫. 在2014年TIOBE四月程式語言排名已經到第30名, 2013基本上都是在50名以外, 而且我相信 這名次會持續在進步. 第一個 go 程式 package main import "fmt“ func main () { fmt.Println("Hello , World!") }
  8. 8. Golang 入門初體驗 Go 安裝 http://golang.org/dl/ Windows: 安裝好 GO 後, 還需要 GCC 編譯環境, 因為 Mac 的 Xcode 本身就有 GCC, windows 沒有, 所以 選擇了 mingw 這個輕量型的 GCC http://blog.jex.tw/blog/2013/12/17/windows-install-gcc-compiler-mingw/ 設定 GOPATH, 這是放一些你自己或 go get from github 存放的地方 1. 在 c:Go 下建立 mygo 資料夾, 並且在 mygo 下建立三個資料夾 src, pkg, bin 2. 設定環境變數 GOROOT : C:Go GOPATH : C:Gomygo PATH : 在最後面加上 ;%GOROOT%bin;%GOPATH%bin;C:Program Files (x86)Gitbin 除了加上 GOROOTbin、GOPATHbin, 也可視需求加上 git bin 的路徑,重新啟動 cmd 使變數 生效
  9. 9. Golang 入門初體驗 Go 執行 https://golang.org/cmd/go/ go run 要撰寫第一個 Hello, World 程式,你可以建立一個 main.go,在當中撰寫以下的內容: package main import "fmt" func main() { fmt.Println("Hello, World") fmt.Println("哈囉!世界!") }
  10. 10. Golang 入門初體驗 Go 執行 每個 .go 原始碼,都必須從 package 定義開始,而對於包括程式進入點 main 函式的 .go 原始碼, 必須是在 package main 之中,為了要能輸出訊息,這邊使用了 fmt 套件(package)之中的 Println 函式,開頭的大寫 P 表示這是個公開的函式,可以在套件之外進行呼叫。 Go 的創建者之一也是 UTF-8 的創建者,因此,Go 可以直接處理多國語言,只要你確定編輯器 編碼為 UTF-8 就可以了,如果你使用 vim,可以在 vim 的命令模式下輸入 :set encoding=utf-8, 或者是在 .vimrc 之中增加一行 set encoding=utf-8。 Go 可以用直譯的方式來執行程式,第一個 Hello, World 程式就是這麼做的,執行 go run 指定 你的原始碼檔名就可以了: $ go run main.go Hello, World 哈囉!世界! package 與 GOPATH
  11. 11. Golang 入門初體驗 Go 執行 那麼,一開始的 package 是怎麼回事?試著先來建立一個 hello.go: package hello import "fmt" func HelloWorld() { fmt.Println("Hello, World") }
  12. 12. Golang 入門初體驗 Go 執行 記得,package 中定義的函式,名稱必須是以大寫開頭,其他套件外的程式,才能進行呼叫,若 函式名稱是小寫,那麼會是套件中才可以使用的函式。 接著,原本的 main.go 修改為: package main import "hello" func main() { hello.HelloWorld() }
  13. 13. Golang 入門初體驗 Go 執行 現在顯然地,main.go 中要用到方才建立的 hello 套件中的 HelloWorld 函式,這時 package 的 設定就會發揮一下效用,你得將 hello.go 移到 src/hello 目錄之中,也就是目錄名稱必須符合 package 設定之名稱。 而 src/hello 的位置,必須是在 GOROOT 底下,或者是 GOPATH 底下,當 Go 需要某個某個套 件中的元素時,會分別到這兩個環境變數的目錄之中,查看是否有相應於套件的原始碼存在。 為了方便,通常會設定 GOPATH,例如,指向目前的工作目錄: export GOPATH=~workspacego 雖然目前 GOPATH 中只一個目錄,不過 GOPATH 中可以設定數個目錄
  14. 14. Golang 入門初體驗 Go 執行 go build 這個命令主要用於測試編譯。在包的編譯過程中,在必要情況下,還可以同時編譯與之關聯的包。 -普通包:執行完go build ,不會產生任何檔,如果需要在$GOPATH/pkg下生成相應檔,則要 執行go install. -main 包:執行完go build,會在目前的目錄下生成一個可執行檔,如果需要在$GOPATH/bin下生成 對應檔,需要執行go install 或使用 go build -o outputpath/ 如果只想編譯某個檔,只需在在後面加上檔案名即可,例如:go build hello.go 非main包在預設情況下編譯輸出的是package名,main包是第一個原始檔案的檔包,也還可以指定編 譯輸出的檔案名,例如,go build -o xialingsc.exe
  15. 15. Golang 入門初體驗 Go 執行 go build go build 會忽略目錄下以"_"或"."開頭的go文件 如果原始程式碼針對不同的作業系統需要不同的處理,那麼可以根據不同的作業系統尾碼來命名檔。 例如,readfile_linux.go,readfile_drawin.go,readfile_windows.go.go build 會選擇性編譯 檔,Linux系統只編譯readfile_linux.go,其他文件則被忽略。
  16. 16. Golang 入門初體驗 Go 執行 go build 如果想編譯原始碼為可執行檔,那麼可以使用 go build,例如,直接 go build main.go,就會在 執行指令的目錄下,產生一個名稱為 main 的可執行檔,可執行檔的名稱是來自己指定的原始碼 檔案主檔名,執行產生出來的可執行檔就會顯示 Hello, World。 你也可以建立一個 bin 目錄,然後執行 go build -o bin/main main.go,這樣產生出來的可執行 檔,就會被放在 bin 底下,如果想將原始碼全部放在 src 底下管理,那麼就將 main.go 放到 src/main 底下,然後執行 go build -o bin/main src/main/main.go。 go install 每次使用 go build,都是從原始碼編譯為可執行檔,這比較沒有效率,如果想要編譯時更有效率 一些,可以使用 go install,例如,在目前既有的目錄與原始碼架構之下,執行 go install main
  17. 17. Golang 入門初體驗 Go 執行 go build ~go |~bin/ | |-main |~pkg/ | `~linux_arm/ | `-hello.a |~src/ | |~hello/ | | `-hello.go | |~main/ | | `-main.go go install packageName 表示要安裝指定名稱的套件,如果是 main 套件,那麼會在 bin 中產生 可執行檔,如果是公用套件,那麼會在 pkg 目錄的 $GOOS_$GOARCH 目錄中產生 .a 檔案
  18. 18. Golang 入門初體驗 Go 執行 go build 可以使用 go env 來查看 Go 使用到的環境變數,例如: $ go env GOARCH="arm" GOBIN="" GOEXE="" GOHOSTARCH="arm" GOHOSTOS="linux" GOOS="linux" GOPATH="/root/workspace/go" GORACE="" GOROOT="/opt/go" GOTOOLDIR="/opt/go/pkg/tool/linux_arm" GO15VENDOREXPERIMENT="" CC="gcc" GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0" CXX="g++" CGO_ENABLED="1"
  19. 19. Golang 入門初體驗 Go 執行 go build .a 檔案是編譯過後的套件,因此,你看到的 hello.a,就是 hello.go 編譯之後的結果,如果編譯 時需要某個套件,而對應的 .a 檔案存在,且原始碼自上次編譯後未曾經過修改,那麼就會直接使 用 .a 檔案,而不是從原始碼開始編譯起。 go clean 用來移除當前源碼包裡編譯生成的檔,這些檔包括,_obj(舊的objects目錄,Makefiles遺留), _test(舊的test目錄),_testmain.go(舊的gotest文件),test.out、build.out(舊的test記錄) *.[568ao] object文件,DIR(.exe)(由go build產生),DIR.test(.ext)(由go test -c產生), MAINFILE(.exe) (由go build MAINFILE.go產生) 該命令最大的作用,清除編譯文件後,上傳git,保持源碼清潔。
  20. 20. Golang 入門初體驗 Go 執行 os.Args 那麼,如果想在執行 Go 程式時使用命令列引數呢?可以使用 os 套件的 Args,例如,寫一個 main.go: package main import "os" import "fmt" func main() { fmt.Printf("Command: %sn", os.Args[0]) fmt.Printf("Hello, %sn", os.Args[1]) }
  21. 21. Golang 入門初體驗 Go 執行 os.Args 是個陣列,索引從 0 開始,索引 0 會是編譯後的可執行檔名稱,索引 1 開始會是你提供 的引數,例如,在執行過 go build 或 go install 之後,如下直接執行編譯出來的執行檔,會產生 的訊息是… $ ./bin/main Justin Command: ./bin/main Hello, Justin go doc
  22. 22. Golang 入門初體驗 Go 執行 fmt 的 Printf,就像是 C 的 printf,可用的格式控制字元可參考 Package fmt 的說明。實際上, Go 本身附帶了說明文件,可以執行 go doc <pkg> <sym>[.<method>] 來查詢說明。例如: $ go doc fmt.Printf func Printf(format string, a ...interface{}) (n int, err error) Printf formats according to a format specifier and writes to standard output. It returns the number of bytes written and any write error encountered.
  23. 23. Golang 入門初體驗 Go 執行 go fmt 幫助格式化寫好的代碼檔,讓寫代碼時不關心格式,寫完後,輕鬆執行go fmt 檔案名.go就好 提高效率。更多的時候可以採用gofmt,同時增加-w的參數,否則格式化結果不會寫入檔,例如: gofmt -w src 來格式整個項目。 go get 動態獲取遠端代碼。這個代碼內部分為兩部分,一是下載源碼包,另一步是執行go install 為了讓go get正常使用,需保證安裝了合適的源碼管理工具,並將這些命令加入到PATH中。 可通過go help remote 瞭解更多。 go test 執行這個命令會自動讀取源碼目錄下名為*_test.go檔,生成並運行測試用的可執行檔。 預設情況下不需要任何參數,也可帶上參數,具體可參見go help testflag
  24. 24. Golang 入門初體驗 Go 執行 go doc 如何查看相應的package文檔呢? 如果是builtin包,可以執行go doc builtin;如果是http包,執行go doc net/http; 查看某個包裡面的函數,類似執行 godoc fmt Println,還可以查看相應代碼 godoc -src fmt Println 很棒的一點是,可以在終端執行godoc -http=:埠號,例如godoc -http=:8080 ,就可以在 流覽器中敲入127.0.0.1:8080進行文檔內容的查看。 其他命令 go fix 用來修復以前老版本的代碼到新版本 go version 查看go當前的版本 go env 查看當前go的環境變數 go list 列出當前全部安裝的package go run 編譯並運行go語言程式
  25. 25. Golang 入門初體驗 Go IDEs IDEs 有以下幾種,使用文字編輯器亦可完成程式編輯,再至Command Line執行編譯 Lite IDE GoSublime Visual Studio Code Goclipse VIM / VIM-go
  26. 26. Golang 入門初體驗 Go 語法 (參考 https://polor10101.gitbooks.io/golang_note/content/about_golang.html) variable 變數 雖然號稱和 c 類似, 不過 go 在變數的命名上有很大的不同, 他是以 type 放後面為原則 以下表示宣告一個變數 x 且他是整數型態. var x int 如果要給他初始值, 有以下幾種方式 給予初始值 var x int = 10 var y = 20 var z int z = 30 k := 40 常數 const PI = 3.1415 const NAME = "Nelson" 常數不需要給定 type, 只要直接給予值即可. 而且不能用 ':=' 的方式給予初始值. 你可以發現每行的結尾少了分號 ';', 是的 go 省略分號, 只要斷行來分就好.
  27. 27. Golang 入門初體驗 Go 語法 函式 函式的宣告方式也和 c 不同 func add( a int , b int){ c := a + b } 如果要回傳東西 func add( a int , b int) int{ c := a + b return c } 但是還是維持 type 在後面的原則 在此在大括號的位置也有規定, 如例子所示
  28. 28. Golang 入門初體驗 Go 語法 函式 你也可以 func add( a int , b int) int{ } 但是不可以採用對齊的方式 func add( a int , b int) int { } 從以上例子來看, 會發現 go 在程式的風格上有強制規定, 不符合規定會有 error
  29. 29. Golang 入門初體驗 Go 語法 函式 有幾點初學的時候有點不習慣 每行 code 不需要分號 ; 大括號的排版方式 import 某個 lib 或是宣告某變數但是實際卻沒有使用 宣告改成這個方式, 官方是說可以增加閱讀性. why? 這部份在其他章節會有描述 另外可以用變數直接指向 function func add(a int,b int) int{ return a+b }
  30. 30. Golang 入門初體驗 Go 語法 關於語法 go 在語法中做了改變, 官方的說法是, 改這樣的原因是因為這樣比較好閱讀. 接著來比較 c 和 go 的語法 以宣告 variable 來看 int add; //c var add int //go go 還多一個 var, 似乎也沒有比較方便 以 function 來看 int add(int a, intb); //c func add(a int, b int)int //go 也還好, 不過比較起來 go 比較容易分辨出是 variable 還是 function, 但是差距也沒有很大, 而且 go 還需要多打 字.
  31. 31. Golang 入門初體驗 Go 語法 關於語法 如果宣告一個 function pointer 然後輸入一個 function pointer 變數 int (*fp)(int (*ff)(int x, int y), int b) //c f func(func(int,int) int, int) int //go c 已經有點讓人混亂了, 且不好閱讀. go 這樣是不是有比較清楚? 個人是覺得有, 還很明顯. 再加個回傳 function pointer 的宣告比較. int (*(*fp)(int (*)(int, int), int))(int, int) //c f func(func(int,int) int, int) func(int, int) int //go 結論 : 真的有差. f := add f(10,20)
  32. 32. Golang 入門初體驗 Go 語法 loop 迴圈 以 c 來說迴圈有 for , while , do while 三個關鍵字. 在 go 裡面只有一個 for 來達到全部 以 for 迴圈來說 c 為 int i = 0; int sum = 0; for( i = 0 ; i < 10 ; ++i ) { sum += i; } 以下為 go 的 for 迴圈範例 sum := 0 for i := 0 ; i < 10 ; ++i { sum += i } 從範例中可以看到 "( )" 省略了, 再來兩個中夸號並不是對齊的
  33. 33. Golang 入門初體驗 Go 語法 loop 迴圈 c 的 do while 迴圈 int i = 0; do{ i += 1 }while( i < 10 ); go 中為 i := 0 for i < 100 { i += 1 } c 的無限 while 迴圈 while(1) { } go 的 for { } 以上為 go 和 c 的迴圈使用比較. 從中可以了解一些語法上 的差別
  34. 34. Golang 入門初體驗 Go 語法 if switch 和 c 不同的是, if 不需要小括號, 另外大括號必須要有, 並且強制是範例的排版方式, 否則會有 error if a > 0 { fmt.Println(a) } 個人是習慣對齊的方法, 不過這樣的強制規定可以讓多人開發專案的程式碼有一致性, 這也是個好處. switch 也是同樣的規定, 並且不需要加上 'break' 如以下所示 switch i { case 1 : fmt.Println(1) case 2 : fmt.Println(2) default : fmt.Println("default") }
  35. 35. Golang 入門初體驗 Go 語法 Array array 的宣告 var a [5]int //宣告一個大小5的 int array var b []int //宣告空的 int array var c = []int{1,2,3,4,5}//宣告一個大小5的 int array, 並給初始值 如果要列印 array 裡面的值, 你可以使用 range 知道 array 目前的 index import "fmt" func main() { var a = [4]int {1,2,3,4} for i := range a { fmt.Println(a[i]) } }
  36. 36. Golang 入門初體驗 Go 語法 Array 初始話也可以改成 var a = [4]int { 1, 2, 3, 4, } 其中 4 的後面記得要有逗號 ','
  37. 37. Golang 入門初體驗 Go 語法 Slice 相對於 array, slice 提供了彈性, 不需要指定大小 是由三個元件組成 ptr len cap 其中 prt 是指向一個 array 的指標, 如圖所示
  38. 38. Golang 入門初體驗 Go 語法 Slice len 為實際資料長度, cap 表示容量 宣告的方式為 a := []int 此時的 len , cap 都為 0 你可以用 make 來宣告變數並指定 len 和 cap 的值 a := make([]int,5,10) 其中 5 為len, 10 為 cap
  39. 39. Golang 入門初體驗 Go 語法 Slice 也可以不指定 cap 寫成 a := make([]int,5) 這時 len 為 5 , cap 為 5 另外給定初始值的宣告 var a = []int {1,2,3,4,5} 如果要一個變數指向 a b := a[2:4] c := a[:]
  40. 40. Golang 入門初體驗 Go 語法 Slice 其中 b 為 3 , 4. a[2:4] 的 2 表示指向 a index = 2 的位置, 4 表示為結尾在 index = 4(不包含), 所以則 length 為 2, 另外由於 array 是連續的, 所以 cap = 3 c 為 1,2,3,4,5 [:] 表示 [0:len(a)], 第一個值如果沒寫則為 0, 第二個沒寫的為 len(a) = 5
  41. 41. Golang 入門初體驗 Go 語法 Slice 所以可以得知 a[:3] 和 a[1:] 個別為 1,2,3 //a[:3] 2,3,4,5 //a[1:] 另外要特別注意的是, b := a[1:3] 並不是 a copy 值給 b, 而是將 b 的指標指向 a ( index 2 ) 的位置 所以這表示如果你改了 b 的值, a 的也會一起改變, 因為他們共用同一個 array. 如果你要兩者是獨立的, 可以使用 copy 的方法 copy(b,c)
  42. 42. Golang 入門初體驗 Go 語法 Slice 這是把 c 的前兩個的值, copy 到 b 中. 為什麼只 copy c 的前兩個?因為 b 的大小只有二, 以小的為主 copy(c,b) 則表示將 b 的值, copy 覆蓋 c 的前兩個值. 另外可以用 append 來增加他的大小 如下所示 import "fmt" func main(){ var a[]int a = append(a,1) a = append(a,2) for i := range a { fmt.Println(a[i]) } }
  43. 43. Golang 入門初體驗 Go 語法 Map 建立一個 map 可以用以下兩種方式 m := make(map[string]int) m := map[string]int{} 定義 age = 16 m["age"] = 16 回傳值, 和 map 是否存在 value , ok := m["age"] 如果是不存在的 key , value = 0 , ok = false value , ok := m["height"]
  44. 44. Golang 入門初體驗 Go 語法 Map 利用 rage 取得 map 中所有的 key 和 value, 並列印 for key, value := range m { fmt.Println("Key:", key, "Value:", value) } 如果要一次宣告多個值, 可以用以下方式 person := map[string]int{ "age" : 16, "height" : 180, "weight" : 6, } https://play.golang.org/p/rPpLGhc9lE
  45. 45. Golang 入門初體驗 Go 語法 Goroutine 在講goroutine之前, 必須先了解 concurrency 和 parllelism的不同 concurrency (併發) vs parallelism (並行) 併發 concurrency 是將 process 切割成多個可執行單位(coroutine), 如果有多個 process 時則在 coroutine 中 交互執行, 這樣不會因為某一個 process 執行太久造成其他 process 無法處理, 會讓你有多工的感覺. 但這並不 會增加執行效率. 總執行時間是一樣的, 如圖一所示. 另外和 thread 不同的是, thread 是屬於 os 層面上的, 且 thread 非常消耗系統資源.
  46. 46. Golang 入門初體驗 Go 語法 Goroutine
  47. 47. Golang 入門初體驗 Go 語法 Goroutine 並行 parallelism 是多個 process 由多個 cpu 去執行, 可以增加執行的效率, 縮短總執行的時間. 如圖二所示
  48. 48. Golang 入門初體驗 Go 語法 Goroutine go 用 goroutine 實現了 concurrency. 使用者只要設定最大的 thread 數量, 和系統是多少CPU, run-time 就會 幫你處理好剩下的 thread 管理, 但為什麼 gorountine 可以提供較好的效能? (以下為個人心得可能有錯)
  49. 49. Golang 入門初體驗 Go 語法 Goroutine 第一. 在創造 goroutine 的資源消耗是很小的, 因為 goroutine 只是一個 function 的入口. 只要很小的 stack 去 記錄即可. 第二. thread 上的管理, 當某個 goroutine 被 block 住, 處理此 goroutine 的 thread 就耗在這上, 此時 run-time 會將其他的 goroutine 轉給此 thread 去執行, 這樣 thread 就不會因為執行某些被 block 的任務則消耗在那邊. 有效的使用 thread. 第三. thread 最多不會超過 $GOMAXPROCS(使用者設定的), 可以確保 thread 不會失控的增加. 綜合以上三點, goroutine 其實就是避免 thread 的不當增加, 有效的使用目前的 thread , 這樣系統資源的消耗就 少了. 不會因為系統的資源不夠造成整體效能的降低. coroutine 資料一 coroutine 資料二 thread 資料 goroutine 資料一 goroutine 資料二 goroutine 資料三
  50. 50. Golang 入門初體驗 Go 語法 goroutine - channels Don't communicate by sharing memory; share memory by communicating. 不同於過去的 muliti thread 的程式開發, 常使用共用變數去做資訊傳遞 (communicate by sharing memory). goroutine 彼此的溝通方式是使用 channel (share memory by communicating). 這樣的方式會讓整個流程在 表現上變得清楚. channels channel 的通訊, 需要一個 sender 和一個 receiver, 當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞. import "fmt" func main(){ s := mack(chan string) //宣告一個 channel 變數 s <- "hello" //寫入 channel (sender) val <- s //讀取 channel (receiver) fmt.Println(val) } 上例說明了如何宣告 channel 變數, 寫入 channel, 讀取 channel.
  51. 51. Golang 入門初體驗 Go 語法 goroutine - channels 但是 code 無法跑, compiler 會顯示 dead lock. 因為執行到 s <- "hello" 這步的時候, sender 就會進入 ready 狀態. 然後就停住了, 也就是他不會執行到 val := <- s . 這時我們建立一個 goroutine 去跑 s <- "hello" import "fmt" func main(){ s := make(chan string) //宣告一個 channel 變數 go func(){ s <- "hello" //寫入 channel (sender) }() val := <- s //讀取 channel (receiver) fmt.Println(val) }
  52. 52. Golang 入門初體驗 Go 語法 goroutine - channels 執行順序就是 1. 建立一個 goroutine //此時 s <- "hello" 還沒執行 2. 執行 val := <- s //s 空的, receiver ready (停住) 3. 執行 s <- "hello" //sender 將訊息寫入 s, sender ready 4. val := <- s //成功讀取 s, (因為 receiver, sender 都 ready) 5. fmt.Println(val) goroutine 不見得會比較慢執行. 不過重點不在這, 就不多描述了. 所以要看執行的順序就要注意這原則 "當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞. " 再舉一個例子, 請問順序式如何?
  53. 53. Golang 入門初體驗 Go 語法 goroutine – channels import "fmt" func main(){ s := make(chan string) go func() { for i := 0; i < 3; i++ { fmt.Println("sender hello",i) s <- fmt.Sprintf("receiver hello %d", i) } }() for i := 0; i < 3; i++ { val := <-s fmt.Println(val) } }
  54. 54. Golang 入門初體驗 Go 語法 goroutine – channels 結果 sender hello 0 sender hello 1 receiver hello 0 receiver hello 1 sender hello 2 receiver hello 2 有對嗎?程式碼順序是這樣 1. 建立一個 goroutine 2. 執行 val := <- s //s 空的, receiver ready (停住) [sender hello 0] 3. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功 [sender hello 1] 4. 執行 s <- fmt.Sprintf.. //s 有值, sender ready(停住) 5. val := <-s //讀到 s 的值 [receiver hello 0] 6. val := <-s //s 空的, receiver ready, 傳訊成功 [receiver hello 1] 7. val := <-s //s 空的, receiver ready (停住) [sender hello 2] 8. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功 9. val := <-s //讀到 s 的值 [sender hello 2] http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
  55. 55. Golang 入門初體驗 Go 語法 goroutine – channels 另外我們可以修改 channel 的大小為 2 import "fmt" func main(){ s := make(chan string,2) go func() { for i := 0; i < 3; i++ { fmt.Println("sender hello",i) s <- fmt.Sprintf("receiver hello %d", i) } }() for i := 0; i < 3; i++ { val := <-s fmt.Println(val) } } 結果 sender hello 0 sender hello 1 sender hello 2 receiver hello 0 receiver hello 1 receiver hello 2 http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
  56. 56. Golang 入門初體驗 Go 語法 defer panic recover defer 先看以下範例 func f(){ for i := 0 ; i < 5 ; i++{ fmt.Println(i) } fmt.Println("f finish") } 此時的結果是 0 1 2 3 4 f finish
  57. 57. Golang 入門初體驗 Go 語法 defer panic recover 如果再 fmt.Println 前面加上 defer func f(){ for i := 0 ; i < 5 ; i++{ defer fmt.Println(i) } fmt.Println("f finish") } 結果就變成 f finish 4 3 2 1 0
  58. 58. Golang 入門初體驗 Go 語法 defer panic recover defer 是讓 fmt.Println(0) , fmt.Println(1) , fmt.Println(2) , fmt.Println(3) , fmt.Println(4) 依序放到清單中, 等到 func f 結束前, 再依據 Last-In-First-Out (LIFO) 的順序 call 清單中的 function. 這樣功能提供了什麼的好處? 我們再看以下的例子
  59. 59. Golang 入門初體驗 Go 語法 defer panic recover func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { return } written, err = io.Copy(dst, src) dst.Close() src.Close() return }
  60. 60. Golang 入門初體驗 Go 語法 defer panic recover 這個例子有個 bug, 就是當 os.Create(dstName) 失敗的時候 function 就會 return, 而 src.Close() 就沒有執行 到了. 所以可以改成這樣
  61. 61. Golang 入門初體驗 Go 語法 defer panic recover func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { src.Close() return } written, err = io.Copy(dst, src) dst.Close() src.Close() return }
  62. 62. Golang 入門初體驗 Go 語法 defer panic recover 但是如果開多個檔案? 那會很麻煩 所以我們利用 defer 來修改 func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src) } 這時不管如何, 都會執行 close function.
  63. 63. Golang 入門初體驗 Go 語法 defer panic recover 但是如果開多個檔案? 那會很麻煩 所以我們利用 defer 來修改 func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src) } 這時不管如何, 都會執行 close function. 參考網站 https://blog.golang.org/defer-panic-and-recover panic recover go 沒有 try catch , 原因是 go 的開發者認為, 當過多 try catch 時 會造成程式碼很難閱讀. 所以提供了 panic recover 優雅的解決這 個問題.
  64. 64. Golang 入門初體驗 Go 後續 GoWeb Go Bot (Line、Facebook Message、Slack、Telegram、 ……..) Go 機器學習 Go 物聯網
  65. 65. Golang 入門初體驗

×