DukeHuangWp
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
###### tags: `GoLang` # GoLang 04.應用範例: ### Go : 語言的包(Package)使用說明 > > 1. 每個程式碼 ``.go``必須歸屬一個package > 2. 歸屬同一個package之 ``.go``變數名稱不得重複 > 3. 歸屬同一個package之 ``.go``檔案必須位於同一資料夾 > 4. import導入package可自訂抬頭名稱,資料夾路徑為 ``%GOPATH%/src``目錄下 > 5. 若要將package編譯成執行檔,必須將主程式歸屬於 ``package main``當中,執行檔將由 ``func init()``然後 ``func main()``開始執行。 > 6. ``func init()``由import內引用package的倒序開始執行,再依自身包``func init()``順序開始執行(同一包可准許內有多個``func init()``)。 > > ### Package使用範例: > > ```graphviz > > digraph{ > > nodesep=0.5 > ranksep=0.5 > graph [bgcolor="#1e1e1e"] > edge [ color="#DDDDDD"] > node [ color="#3e4045" penwidth=10 fillcolor="#3e4045" fontcolor="#DDDDDD" style=filled shape=ellipse fixedsize=true width=1.9] > > "\%GOPATH\%\" -> "src\" -> "Lesson2\" -> "Package演示\" -> {"Package_FolderTest1\" "Package_FolderTest2\" "Package_FolderTest3\"} > > "Package演示\" -> "Package_main.go" > [fillcolor=Blue] > > "Package_FolderTest1\" -> "Package_Test1.go" > [fillcolor=Blue] > > "Package_FolderTest2\" -> {"Package_Test2-1.go" "Package_Test2-2.go"} > [fillcolor=Blue] > > "Package_FolderTest3\" -> {"Package_Test3-1.go" "Package_Test3-2.go"} > [fillcolor=Blue] > } > > ``` > > > ``Package_main.go:`` > ``` go= > package main > import ( > Package_CustomTest1 "Lesson2/Package演示/Package_FolderTest1" > Package_CustomTest2 "Lesson2/Package演示/Package_FolderTest2" > Package_CustomTest3 "Lesson2/Package演示/Package_FolderTest3" > "fmt" > ) > > func main() { > > fmt.Println(Package_CustomTest1.Gstring_Name_Test1) > fmt.Println(Package_CustomTest2.Gstring_Name_Test2_1) > fmt.Println(Package_CustomTest2.Gstring_Name_Test2_2) > fmt.Println(Package_CustomTest3.Gstring_Name_Test2_1) > fmt.Println(Package_CustomTest3.Gstring_Name_Test2_2) > > } > ``` > > ``Package_Test1.go:`` > ``` go= > //package main可透過import導入並使用大寫開頭名稱之變數 > //package main不可由import導入小寫開頭名稱之變數 > package Package_Test1 > var gstring_Name_Test0 = "不可import" > var Gstring_Name_Test1 = "測試1" > ``` > > ``Package_Test2-1.go:`` > ``` go= > //歸屬同一個package(同目錄)的Package_Test2-1.go之變數名稱不得重複 > package Package_Test2 > var Gstring_Name_Test2_1 = "測試2-1" > ``` > > ``Package_Test2-2.go:`` > ``` go= > //歸屬同一個package(同目錄)的Package_Test2-2.go之變數名稱不得重複複 > package Package_Test2 > var Gstring_Name_Test2_2 = "測試2-2" > ``` > > ``Package_Test3-1.go:`` > ``` go= > //package main可使用import更名避免重複的package名稱 > package Package_Test2 > var Gstring_Name_Test2_1 = "測試2-1" > ``` > > ``Package_Test2-2.go:`` > ``` go= > //package main可使用import更名避免重複的package名稱 > package Package_Test2 > var Gstring_Name_Test2_2 = "測試2-2" > ``` ### Go : 驗證CG記憶體回收機制 > ```go= > package main > > import ( > "fmt" > "log" > "runtime"package main > > import ( > "fmt" > "log" > "runtime" > ) > > func main() { > > var m0 runtime.MemStats > println() > log.Println("At begin:") > PrintMemUsage(m0) > // 2020/04/06 11:09:40 At begin: > // Alloc(當前堆上對象佔用的內存大小) = 0 MiB > // Sys(程序從作業系統總共申請的內存大小) = 6 MiB > // NumGC(垃圾回收運行的次數) = 0 > > var m1 runtime.MemStats > var overall1 []float64 > for i := 0; i < 1136640; i++ { > overall1 = append(overall1, 1) > } > println() > log.Println("nothing to do:") > PrintMemUsage(m1) > println(overall1) > overall1 = nil //僅為了計算方便,不影響測試結果 > // 2020/04/06 11:09:40 nothing to do: > // Alloc(當前堆上對象佔用的內存大小) = 8 MiB > // Sys(程序從作業系統總共申請的內存大小) = 37 MiB > // NumGC(垃圾回收運行的次數) = 9 > // [1136640/1136640]0xc00127c000 > > var m2 runtime.MemStats > var overall2 []float64 > for i := 0; i < 1136640; i++ { > overall2 = append(overall2, 1) > } > overall2 = nil > println() > log.Println("nil :") > PrintMemUsage(m2) > println(overall2) > // 2020/04/06 11:09:40 nil : > // Alloc(當前堆上對象佔用的內存大小) = 0 MiB > // Sys(程序從作業系統總共申請的內存大小) = 37 MiB > // NumGC(垃圾回收運行的次數) = 17 > // [0/0]0x0 > > // Force GC to clear up, should see a memory drop > var m3 runtime.MemStats > var overall3 []float64 > for i := 0; i < 1136640; i++ { > overall3 = append(overall3, 1) > } > runtime.GC() > println() > log.Println("Forece GC:") > PrintMemUsage(m3) > // 2020/04/06 11:09:40 Forece GC: > // Alloc(當前堆上對象佔用的內存大小) = 0 MiB > // Sys(程序從作業系統總共申請的內存大小) = 37 MiB > // NumGC(垃圾回收運行的次數) = 27 > > > var m4 runtime.MemStats > var overall4 []float64 > p4 := &overall4 > for i := 0; i < 1136640; i++ { > overall4 = append(overall4, 1) > } > runtime.GC() > println() > log.Println("Forece GC (use pointer):") > PrintMemUsage(m4) > println(p4) > // 2020/04/06 11:09:40 Forece GC: > // Alloc(當前堆上對象佔用的內存大小) = 8 MiB > // Sys(程序從作業系統總共申請的內存大小) = 37 MiB > // NumGC(垃圾回收運行的次數) = 37 > // 0xc00010ff60 > > > } > > func PrintMemUsage(m runtime.MemStats) { > runtime.ReadMemStats(&m) > > // For info on each, see: https://golang.org/pkg/runtime/#MemStats > fmt.Printf("Alloc(當前堆上對象佔用的內存大小) = %v MiB\n", byteToMiB(m.Alloc)) > //fmt.Printf("TotalAlloc(堆上總共分配出的內存大小) = %v MiB\n", byteToMiB(m.TotalAlloc)) > fmt.Printf("Sys(程序從作業系統總共申請的內存大小) = %v MiB\n", byteToMiB(m.Sys)) > fmt.Printf("NumGC(垃圾回收運行的次數) = %v\n", m.NumGC) > > } > > func byteToMiB(b uint64) uint64 { > return b / 1024 / 1024 > } > ``` ### Go : 氣泡排序法(Bubble Sort): > 氣泡排序演算法的運作如下: > 1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。 > 2.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。 > 這步做完後,最後的元素會是最大的數。 > 3.針對所有的元素重複以上的步驟,除了最後一個。 > 4.持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。 ><iframe width=100% height="315" src="https://www.youtube.com/embed/O2w-gJjU-PU?start=266" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> > > ```go > package main > import "fmt" > func main() { > > var vSlice = []int{51, 99, 36, 66, 62} > fmt.Println("排序前:", vSlice) > fmt.Println("最後結果:", fcBubbleSort_Slice(vSlice)) > > } > > func fcBubbleSort_Slice(inputSlice []int) []int { > for index1 := 1; index1 < len(inputSlice); index1++ { > // 第一層迴圈負責控制排序輪迴數 > // 每輪都從第二個元素開始,將最大的值交換到最後一位 > for index2 := 0; index2 < len(inputSlice)-index1; index2++ { > // 第二層迴圈負責比較兩元素大小判斷是否交換 > if inputSlice[index2] > inputSlice[index2+1] { > inputSlice[index2], inputSlice[index2+1] = inputSlice[index2+1], inputSlice[index2] > } > } > fmt.Printf("第%v次排序結果: %v\n", index1, inputSlice) > } > return inputSlice > } > ``` ### Go : 反射包(reflect)介紹 > ```go= > package main > > import ( > "fmt" > "reflect" > ) > > func fc_ReflectExample1(if_input interface{}) { > fmt.Printf("%v (%T)\n", reflect.ValueOf(if_input), reflect.ValueOf(if_input)) > var vi_int = 1 + reflect.ValueOf(if_input).Int() //使用反射之內建方法進行型別斷言 > fmt.Printf("%v (%T)\n", vi_int, vi_int) > } > > type ty_Custom struct { > Name string > ID uint > } > > func fc_ReflectExample2(if_input interface{}) { > if st_Custom, TypePass := if_input.(ty_Custom); TypePass { > fmt.Printf("%v (%T)\n", st_Custom, st_Custom) > fmt.Printf("%v (%T)\n", st_Custom.Name, st_Custom.Name) > } > > } > > func main() { > > fc_ReflectExample1(9) > println() > fc_ReflectExample2(ty_Custom{Name: "測試"}) > > // 9 (reflect.Value) > // 10 (int64) > > // {測試 0} (main.ty_Custom) > // 測試 (string > > } > ``` > > #### reflect包常用函式與方法: > | 函式名稱 | 說明| 輸入 | 輸出類型 | > | - | - | - | - | > |reflect.ValueOf(任意變數)|回傳變數值|任意變數|(reflect.Value)| > |reflect.TypeOf(任意變數)|回傳變數型別名稱|任意變數|(*reflect.rtype)| > |(reflect.Value型別變數).Kind()|回傳變數底層型別|reflect.Value型別|(string)| > |(reflect.Value型別變數).Elem()|回傳指標之變數值|具備指標型別|(reflect.Value))| > |(reflect.Value型別變數).Elem().FieldByName(屬性名稱)|回傳結構體該屬性值|(reflect.Value型別)和屬性名稱|(reflect.Value)| > |(reflect.Value型別變數名稱).CanSet()|判斷該變數是否能修改值|reflect.Value型別|(bool)| > |(reflect.Value型別變數名稱).Set(reflect.Value(數值))|直接修改該變數值|符合型別之數值|| > |(*reflect.rtype).Name()|回傳變數型別名稱|(*reflect.rtype)|型別名稱(string)| > > ``` > #### reflect Kind() 反射type型別名稱常數 > const ( > Invalid Kind = iota //nil屬此類 > Bool > Int > Int8 > Int16 > Int32 > Int64 > Uint > Uint8 > Uint16 > Uint32 > Uint64 > Uintptr > Float32 > Float64 > Complex64 > Complex128 > Array > Chan > Func > Interface > Map > Ptr > Slice > String > Struct > UnsafePointer > ) > ``` > > ```go= > package main > > import ( > "fmt" > "reflect" > ) > > func fc_ReflectExample1(if_input interface{}) { > fmt.Printf("%v (%T)\n", reflect.ValueOf(if_input), reflect.ValueOf(if_input)) > var vi_int = 1 + reflect.ValueOf(if_input).Int() //使用反射之內建方法進行型別斷言 > fmt.Printf("%v (%T)\n", vi_int, vi_int) > } > > type ty_Custom struct { > Name string > ID uint > } > > func fc_ReflectExample2(if_input interface{}) { > if st_Custom, TypePass := if_input.(ty_Custom); TypePass { > fmt.Printf("%v (%T)\n", st_Custom, st_Custom) > fmt.Printf("%v (%T)\n", st_Custom.Name, st_Custom.Name) > } > > } > > func main() { > > fc_ReflectExample1(9) > println() > fc_ReflectExample2(ty_Custom{Name: "測試"}) > > // 9 (reflect.Value) > // 10 (int64) > > // {測試 0} (main.ty_Custom) > // 測試 (string > > } > ``` > ### Go 反射包(reflect)應用: > > ```go= > package main > import ( > "fmt" > "reflect" > ) > > type ty_Example struct { > F0 uint > F1 string > } > > func main() { > > fmt.Printf("%v\n", reflect.ValueOf("Testing")) //Testing > fmt.Printf("%T\n", reflect.ValueOf("Testing")) //reflect.Value > fmt.Printf("%v\n", reflect.ValueOf("Testing").Kind()) //string > fmt.Printf("%T\n", reflect.ValueOf("Testing").Kind()) //reflect.Kind > //fmt.Printf("%v\n", reflect.ValueOf("Testing").Elem()) //panic: reflect: call of reflect.Value.Elem on string Value > println() > > var vi_int int = 1 > //var rVO = reflect.ValueOf(&vi_int) > var vipr_int *int = &vi_int > var rVO = reflect.ValueOf(vipr_int) > > fmt.Printf("%v\n", rVO.Elem()) //1 > fmt.Printf("%T\n", rVO.Elem()) //reflect.Value > fmt.Printf("%v\n", rVO.Elem().CanSet()) //true > fmt.Printf("%T\n", rVO.Elem().CanSet()) //bool > rVO.Elem().Set(reflect.ValueOf(99)) > println(vi_int) //99 > println() > > var st_Example = ty_Example{F0: 1, F1: "測試"} > fmt.Printf("%v\n", reflect.ValueOf(&st_Example).CanSet()) //false > fmt.Printf("%T\n", reflect.ValueOf(&st_Example).CanSet()) //bool > fmt.Printf("%v\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1")) //測試 > fmt.Printf("%T\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1")) //reflect.Value > fmt.Printf("%v\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1").CanSet()) //true > fmt.Printf("%T\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1").CanSet()) //bool > reflect.ValueOf(&st_Example).Elem().FieldByName("F1").Set(reflect.ValueOf("修改")) > fmt.Println(st_Example) //{1 修改} > println() > > } > ``` > > ```go= > package main > import ( > "fmt" > "reflect" > ) > > type ty_Json struct { > Name string `json:"jsname"` > Age int `json:"jsage"` > } > > func main() { > > st_User := ty_Json{ > "測試", > 20, > } > > fmt.Println(reflect.TypeOf(st_User)) //(0x4adaa0,0x487ba0) > fmt.Println(reflect.TypeOf(st_User).Field(0).Name) //name > fmt.Println(reflect.TypeOf(st_User).Field(0).Type) //string > fmt.Println(reflect.TypeOf(st_User).Field(0).Tag) //json:"jsname" > > fmt.Println(reflect.ValueOf(st_User).FieldByName("Name")) //測試 > fmt.Println(reflect.ValueOf(st_User).FieldByName("Name").Type()) //測試 > > println() > > for index := 0; index < reflect.ValueOf(st_User).NumField(); index++ { > if reflect.ValueOf(st_User).Field(index).CanInterface() { //判斷是否可導出屬性 > fmt.Printf("%v (%v %v %v)\n", > reflect.ValueOf(st_User).Field(index).Interface(), > reflect.TypeOf(st_User).Field(index).Name, > reflect.TypeOf(st_User).Field(index).Type, > reflect.TypeOf(st_User).Field(index).Tag) > } > } > // 測試 (Name string json:"jsname") > // 20 (Age int json:"jsage") > > } > ``` ### Go : 語言時間與日期包(time) > 官方文檔: **Golang** → **package time** → **type Duration** > 內建計時常數如下(**const**): > > Nanosecond Duration = 1 (最小計時單位) > Microsecond = 1000 * Nanosecond > Millisecond = 1000 * Microsecond > Second = 1000 * Millisecond > Minute = 60 * Second > Hour = 60 * Minute > > **編譯時使用計時常數不可作除法運算**(設計目的是為了避免影響精確度) > > > > > ``` go= > package main > import ( > "fmt" > "time" > ) > > func main() { > > vNow := time.Now() > fmt.Printf("vNow = %v (%T)\n", vNow, vNow) > > fmt.Printf("年 = %v (%T)\n", vNow.Year(), vNow.Year()) > fmt.Printf("月 = %v (%T)\n", vNow.Month(), vNow.Month()) > fmt.Printf("月 = %v (%T)\n", int(vNow.Month()), int(vNow.Month())) > fmt.Printf("日 = %v (%T)\n", vNow.Day(), vNow.Day()) > fmt.Printf("星期 = %v (%T)\n", vNow.Weekday(), vNow.Weekday()) > fmt.Printf("小時 = %v (%T)\n", vNow.Hour(), vNow.Hour()) > fmt.Printf("分鐘 = %v (%T)\n", vNow.Minute(), vNow.Minute()) > fmt.Printf("秒 = %v (%T)\n", vNow.Second(), vNow.Second()) > > fmt.Printf("當前時間 %04d-%02d-%02d(星期%02d) %02d:%02d:%02d\n", > time.Now().Year(), int(time.Now().Month()), time.Now().Day(), time.Now().Weekday(), > vNow.Hour(), vNow.Minute(), vNow.Second()) > > fmt.Printf(vNow.Format("2006/01/02 15:04:05") + "\n") > > fmt.Printf(vNow.Format("2006/01/02") + "\n") > > fmt.Printf(vNow.Format("15:04:05") + "\n") > > fmt.Printf("Unix時間戳:%v UnixNano時間戳%v\n", vNow.Unix(), vNow.UnixNano()) > > vCounterA := fcStartTimeCounter(0) > //計數5秒鐘 > for i := 0; i < 5; i++ { > > fmt.Println(i, "秒") > time.Sleep(time.Second) > } > > fmt.Printf("總共經過了: %0.3f秒\n", float64(fcStopTimeCounter(vCounterA))/(1000*1000*1000)) > > > vCounterB := time.Now() > for i := 0; i < 5; i++ { > > fmt.Println(i, "秒") > time.Sleep(time.Second) > } > fmt.Printf("總共經過了: %0.3f秒\n",time.Now().Sub(vCounterB).Seconds()) > } > > // const ( > // Nanosecond Duration = 1 > // Microsecond = 1000 * Nanosecond > // Millisecond = 1000 * Microsecond > // Second = 1000 * Millisecond > // Minute = 60 * Second > // Hour = 60 * Minute > // ) > > func fcStartTimeCounter(input int64) int64 { > fmt.Printf("\n計時開始由 %0.3f 秒開始計時", float64(input)/(1000^3)) > return time.Now().UnixNano() + input > } > > func fcStopTimeCounter(input int64) int64 { > return time.Now().UnixNano() - input > } > > ``` > > ### Go 官方json包(json): > ```go > package main > > import ( > "encoding/json" > "fmt" > ) > > type User struct { > ID int > Name string > Money float64 > Skills []string > Relationship map[string]string > Identification Identification > } > > type Identification struct { > Phone bool > Email bool > } > > func main() { > user := User{ > ID: 1, > Name: "Tony", > Skills: []string{"program", "rich", "play"}, > Relationship: map[string]string{ > "Dad": "Hulk", > "Mon": "Natasha", > }, > Identification: Identification{ > Phone: true, > Email: false, > }, > } > b, err := json.Marshal(user) > if err != nil { > fmt.Println("error:", err) > } > fmt.Println(string(b)) > //{"ID":1,"Name":"Tony","Money":0,"Skills":["program","rich","play"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"Phone":true,"Email":false}} > } > > > package main > > import ( > "encoding/json" > "fmt" > ) > > type User struct { > ID int > Name string > Money float64 > Skills []string > Relationship map[string]string > Identification Identification > } > > type Identification struct { > Phone bool `json:"phone"` > Email bool `json:"email,E-Mail"` > } > > func main() { > var jsonBlob = []byte(`{"ID":1,"Name":"Tony","Money":0,"Skills":["program","rich","play"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"phone":true,"E-Mail":false}}`) > > var user User > err := json.Unmarshal(jsonBlob, &user) > if err != nil { > fmt.Println("error:", err) > } > fmt.Printf("%+v", user) > //{ID:1 Name:Tony Money:0 Skills:[program rich play] Relationship:map[Dad:Hulk Mon:Natasha] Identification:{Phone:true Email:false}} > } > > > package main > > import ( > "encoding/json" > "fmt" > ) > > type User struct { > ID int > Name string > Money float64 `json:",string"` > Skills []string > Relationship map[string]string > Identification Identification > Career string > Responsibility interface {} > } > > type Identification struct { > Phone bool `json:"phone"` > Email bool `json:"email"` > } > > func main() { > var jsonBlob = []byte(`[ > { > "ID":1, > "Name":"Tony", > "Career":"Engineer", > "Responsibility":{ > "skill":"PHP&Golang&Network", > "description":"coding" > } > }, > { > "ID":2, > "Name":"Jim", > "Career":"Manager", > "Responsibility":{ > "experienced":true > } > } > ]`) > > var users []User > if err := json.Unmarshal(jsonBlob, &users); err != nil { > fmt.Println("error:", err) > } > fmt.Printf("%#v\n", users) //[]main.User{main.User{ID:1, Name:"Tony", Money:0, Skills:[]string(nil), Relationship:map[string]string(nil), Identification:main.Identification{Phone:false, Email:false}, Career:"Engineer", Responsibility:map[string]interface {}{"description":"coding", "skill":"PHP&Golang&Network"}}, main.User{ID:2, Name:"Jim", Money:0, Skills:[]string(nil), Relationship:map[string]string(nil), Identification:main.Identification{Phone:false, Email:false}, Career:"Manager", Responsibility:map[string]interface {}{"experienced":true}}} > > fmt.Println(users[0].Responsibility.(map[string]interface{})["description"].(string)) //coding > fmt.Println(users[1].Responsibility.(map[string]interface{})["experienced"].(bool)) //true > } > > package main > > import ( > "encoding/json" > "fmt" > ) > > type User struct { > ID int > Name string > Money float64 `json:",string"` > Skills []string > Relationship map[string]string > Identification Identification > Career string > Responsibility json.RawMessage > } > > type Identification struct { > Phone bool `json:"phone"` > Email bool `json:"email"` > } > > type Engineer struct { > Skill string `json:"skill"` > Description string `json:"description"` > } > > type Manager struct { > Experienced bool `json:"experienced"` > } > > func main() { > var jsonBlob = []byte(`[ > { > "ID":1, > "Name":"Tony", > "Career":"Engineer", > "Responsibility":{ > "skill":"PHP&Golang&Network", > "description":"coding" > } > }, > { > "ID":2, > "Name":"Jim", > "Career":"Manager", > "Responsibility":{ > "experienced":true > } > } > ]`) > > var users []User > if err := json.Unmarshal(jsonBlob, &users); err != nil { > fmt.Println("error:", err) > } > > for _, user := range users { > switch user.Career { > case "Engineer": > var responsibility Engineer > if err := json.Unmarshal(user.Responsibility, &responsibility); err != nil { > fmt.Println("error:", err) > } > fmt.Println(responsibility.Description) //coding > case "Manager": > var responsibility Manager > if err := json.Unmarshal(user.Responsibility, &responsibility); err != nil { > fmt.Println("error:", err) > } > fmt.Println(responsibility.Experienced) //true > default: > fmt.Println("warning:", "don't exist") > } > } > } > ``` ### Go : 檔案管理包(os.File): > #### os.file包使用說明: > | 函式名稱 | 說明 | 輸入 | 輸出類型:::: | > | - | - | - | - | > | os.Open(路徑) |打開路徑中的檔案,並將輸出該文件的指標|(string)|(*file error)| > | (*file).Close() |將關閉file指標所指向檔案,移除移除該file指標|(string)|(error)| > > ```go > package FileSystem > import ( > "bufio" > "errors" > "io" > "io/ioutil" > "net/http" > "os" > "strconv" > ) > > // os.O_WRONLY: 只寫 > // os.O_CREATE: 創建文件(如果文件不存在) > // os.O_RDONLY: 只讀 > // os.O_RDWR: 讀寫皆可 > // os.O_APPEND: 尾部加入 > // os.O_TRUNC: 清空(文件存在情況下) > // 第三個參數設置權限控制 > > > > func fc_GetPWD() string { > vs_WorkingDir, _ := os.Getwd() > return vs_WorkingDir > } > > func fc_SetPWD(FilePathInput string) error { > err := os.Chdir(FilePathInput) > return err > } > > func fc_GetEnv(EnvVarName string) (EnvVarValue string) { > return os.Getenv(EnvVarName) > } > > func fc_GetAllEnv(EnvVarName string) (AllEnvVarValues []string) { > return os.Environ() > } > > func fc_GetPathList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > FolderList = append(FolderList, value.Name()) > } > return FolderList, nil > } > > func fc_GetFolderList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > if value.IsDir(){ > FolderList = append(FolderList, value.Name()) > } > } > return FolderList, nil > } > > func fc_GetFileList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > if !value.IsDir(){ > FolderList = append(FolderList, value.Name()) > } > } > return FolderList, nil > } > > func fc_FileMove(FilePathInput, FilePathOutput string) error { > return os.Rename(FilePathInput, FilePathOutput) > } > > func fc_SetEnv(EnvVarName, EnvVarValue string) error { > return os.Setenv(EnvVarName, EnvVarValue) > } > > func fc_IsFileModeCode(vs_chmod string) bool { > if len(vs_chmod) == 3 || len(vs_chmod) == 4 { > _, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) > if err_chmodCheck == nil { > for _, value := range vs_chmod { > if value == '8' || value == '9' { > return false > } > } > return true > } > } > return false > } > > func fc_FileModeEnCode(vs_chmod string) (vs_ModeCodestring string, err error) { > switch len(vs_chmod) { > case 1: //r、w表示同時適用OWNER(Windows,Unix) > switch vs_chmod { > case "r": > return "0200", nil > case "w": > return "0400", nil > } > case 2: //rw兩字表示同時適用OWNER(Windows,Unix) > if vs_chmod == "rx" || vs_chmod == "xr" { > return "0200", nil > } else if vs_chmod == "wx" || vs_chmod == "xw" { > return "0400", nil > } else if vs_chmod == "rw" || vs_chmod == "wr" { > return "0600", nil > } > case 3: //rwx三字表示同時適用OWNER(Windows,Unix),777三數字僅適用Unix > switch vs_chmod { > case "rwx", "rxw", "xrw", "xwr", "wrx", "wxr": > return "0700", nil > default: > if fc_IsFileModeCode(vs_chmod) { > return "0" + vs_chmod, nil > } > } > case 4: > if fc_IsFileModeCode(vs_chmod) { > return vs_chmod, nil > } > case 9: > var vu_ower, vu_group, vu_others, vu_sum uint64 > for index, value := range vs_chmod { > switch value { > case 'r': > vu_sum = vu_sum + 4 > case 'w': > vu_sum = vu_sum + 2 > case 'x': > vu_sum = vu_sum + 1 > case '-': > continue > default: > return "", errors.New("Bad chmod input") > } > > switch index { > case 2: > vu_ower = vu_sum > vu_sum = 0 > case 5: > vu_group = vu_sum > vu_sum = 0 > case 8: > vu_others = vu_sum > case 9: > return "", errors.New("Bad chmod input") > } > } > > if vu_ower > 7 || vu_group > 7 || vu_others > 7 { > return "", errors.New("Bad chmod input") > } else { > return "0" + strconv.FormatUint(vu_ower, 10) + strconv.FormatUint(vu_group, 10) + strconv.FormatUint(vu_others, 10), nil > } > > } > return "", errors.New("Bad chmod input") > } > > func fc_IsExist(FilePathInput string) bool { > if _, err := os.Stat(FilePathInput); os.IsExist(err) { > return false > } > return true > } > > func fc_IsNotExist(FilePathInput string) bool { > if _, err := os.Stat(FilePathInput); os.IsNotExist(err) { > return true > } > return false > } > > func fc_CreatFile(FilePathInput string) error { > _, err := os.Create(FilePathInput) //666 > return err > } > > func fc_CreatFolder(FilePathInput, vs_chmod string) error { > var err error > if vs_chmod == "" { > err = os.MkdirAll(FilePathInput, 0777) > return err > } > > vu_chmodNum, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) > if err_chmodCheck != nil { > err = os.MkdirAll(FilePathInput, 0777) > } else { > err = os.MkdirAll(FilePathInput, os.FileMode(vu_chmodNum)) > } > > return err > } > > func fc_RemovePath(FilePathInput string) error { > err := os.RemoveAll(FilePathInput) > return err > } > > func fc_RemoveFile(FilePathInput string) error { > ty_FileStat, err := os.Stat(FilePathInput) > if !ty_FileStat.IsDir() { > err = os.Remove(FilePathInput) > return err > } else { > return errors.New("It's a Folder not File") > } > } > > func fc_RemoveFolder(FilePathInput string) error { > ty_FileStat, err := os.Stat(FilePathInput) > if ty_FileStat.IsDir() { > err = os.Remove(FilePathInput) > return err > } else { > return errors.New("It's a File not Empty-Folder") > } > } > > func fc_ReadFile(FilePathInput string) (string, error) { > > sl_Output, err := ioutil.ReadFile(FilePathInput) > if err != nil { > return "", err > } else { > return string(sl_Output), nil > } > > } > > func fc_ReadBufFile(FilePathInput string, BufSize int64) (string, error) { > > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return "", err > } > defer pty_OpenFile.Close() > > pty_BufReader := bufio.NewReader(pty_OpenFile) > sl_Output := make([]byte, BufSize) > > _, err = pty_BufReader.Read(sl_Output) > if err != nil { > return "", err > } else { > return string(sl_Output), nil > } > > } > > func fc_ClearFile(FilePathInput string) error { > > _, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_TRUNC, 0222) > return err > } > > func fc_AppendFile(FilePathInput string, WriteString string) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > pty_NewWriter := bufio.NewWriter(pty_OpenFile) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_AppendBufFile(FilePathInput string, WriteString string, vi_Bufsize int) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 > pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_WriteNewFile(FilePathInput string, WriteString string) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > pty_NewWriter := bufio.NewWriter(pty_OpenFile) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_WriteBufNewFile(FilePathInput string, WriteString string, vi_Bufsize int) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 > pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_UrlDownload(SavePathInput string, UrlInput string) error { > > // Get the data > pty_HttpRESP, err := http.Get(UrlInput) > if err != nil { > return err > } > defer pty_HttpRESP.Body.Close() > > // Create the file > pty_FileOut, err := os.Create(SavePathInput) > if err != nil { > return err > } > defer pty_FileOut.Close() > > // Write the body to file > _, err = io.Copy(pty_FileOut, pty_HttpRESP.Body) > return err > } > > ``` > > ``FileMode:`` > | 函式名稱 | 說明 | > | - | - | > | O_RDONLY | 只讀模式打開文件 | > | O_WRONLY | 只寫模式打開文件 | > | O_RDWR | 讀寫模式打開文件 | > | O_APPEND | 寫操作時將數據附加到文件尾部 | > | O_CREAT | 如果不存在將創建一個新文件 | > | O_EXCL | 和O_CREATE配合使用,文件必須不存在 | > | O_SYNC | 打開文件用於同步I/O | > | O_TRUNC | 如果可能,打開時清空文件 | > ### Go : 參數命令列(os&flag)應用: > ```go= > package main > > import ( > "flag" > "fmt" > "os" > ) > > func main() { > > //os.Args為string切片類型 > fmt.Printf("一共接收到: %v 個參數 (%T)\n", len(os.Args), os.Args) > > for index, value := range os.Args { > fmt.Printf("os.Args[%v]=%v\n", index, value) > } //os.Args命令列參數具備次序性 > > fmt.Println() > fmt.Println() > //////////////////////////////// > > var user string > var pwd string > var port int > > flag.StringVar(&user, "u", "預設用戶名", "用戶名") > flag.StringVar(&pwd, "pwd", "", "密碼") > flag.IntVar(&port, "port", 0, "Port") > > flag.Parse() //flag解析命令列參數 > > fmt.Printf("User=%v\nPwd=%v\nPort=%v\n", user, pwd, port) > > // cmd.exe -u 123 -pwd "密碼測試" -port 00 > // 一共接收到: 7 個參數 ([]string) > // os.Args[0]=cmd.exe > // os.Args[1]=-u > // os.Args[2]=123 > // os.Args[3]=-pwd > // os.Args[4]=密碼測試 > // os.Args[5]=-port > // os.Args[6]=00 > > // User=123 > // Pwd=密碼測試 > // Port=0 > > } > ``` > ### Go : 常用資料格式(json)應用: > ``json.Marshal`` > ```go= > package main > > import ( > "encoding/json" > "fmt" > ) > > func main() { > > ////////////////////////////////////////////////////////////////// > // 將結構體輸出成json格式 > type stMonster struct { > Name string //json包輸入變數必須大寫 > Age int > Weight float64 > } > > var oMonster = stMonster{ > Name: "名稱", > Age: 99, > } > > vData, err := json.Marshal(&oMonster) > if err != nil { > fmt.Printf("json.Marshal錯誤 : %v\n", err) > } else { > fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) > } > // json.Marshal解析結果 : {"Name":"名稱","Age":99,"Weight":0} > ///////////////////////////////////////////////////////////////// > > ////////////////////////////////////////////////////////////////// > // 將結構體輸出成json格式 > type stMonsterJ struct { > Name string `json:"json名稱"` > Age int `json:"json年齡"` > Weight float64 `json:"json重量"` > } > > var oMonsterJ = stMonsterJ{ > Name: "JJJJ", > Age: 00, > Weight: 0.0, > } > > vData, err = json.Marshal(&oMonsterJ) > if err != nil { > fmt.Printf("json.Marshal錯誤 : %v\n", err) > } else { > fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) > } > //json.Marshal解析結果 : {"json名稱":"JJJJ","json年齡":0,"json重量":0} > ///////////////////////////////////////////////////////////////// > > ///////////////////////////////////////////////////////////////// > // 將map輸出成json格式 > var mData map[string]interface{} > mData = make(map[string]interface{}) > mData["Name"] = "名稱測試" > mData["Age"] = 18 > mData["Weight"] = 99.0 > > vData, err = json.Marshal(&mData) > if err != nil { > fmt.Printf("json.Marshal錯誤 : %v\n", err) > } else { > fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) > } > //json.Marshal解析結果 : {"Age":18,"Name":"名稱測試","Weight":99} > ///////////////////////////////////////////////////////////////// > > ///////////////////////////////////////////////////////////////// > // 將切片加入空接口並寫入map元素輸出成json格式 > var sSlice []map[string]interface{} > > var mData1 map[string]interface{} > mData1 = make(map[string]interface{}) > mData1["Name"] = "名稱測試" > mData1["Age"] = 18 > mData1["Weight"] = 99.0 > > var mData2 map[string]interface{} > mData2 = make(map[string]interface{}) > mData2["Name"] = "名稱測試" > mData2["Age"] = 18 > mData2["Weight"] = 99.0 > > sSlice = append(sSlice, mData1, mData2) > > vData, err = json.Marshal(sSlice) > if err != nil { > fmt.Printf("json.Marshal錯誤 : %v\n", err) > } else { > fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) > } > //json.Marshal解析結果 : [{"Age":18,"Name":"名稱測試","Weight":99},{"Age":18,"Name":"名稱測試","Weight":99}] > ///////////////////////////////////////////////////////////////// > > } > > ``` > > ``json.Unmarshal`` > ```go= > package main > > import ( > "encoding/json" > "fmt" > ) > > func main() { > var err error > > sSlice := []byte(`{"Name":"柏崎星奈","Age":16,"Married":false}`) > // interface 可以接收任何類型的值 > var mMap map[string]interface{} > err = json.Unmarshal(sSlice, &mMap) //Unmarshal只能接收 > if err != nil { > panic(err) > } > fmt.Println("Name: ", mMap["Name"]) > fmt.Println("Age: ", mMap["Age"]) > fmt.Printf("Married: %v\n", mMap["Married"].(bool)) // interface 也可以直接轉成你要的型別 > fmt.Println() > > // Name: 柏崎星奈 > // Age: 16 > // Married: false > > type Identification struct { > Phone string `json:"JPhone"` > Email string `json:"JEmail"` > } > > type User struct { > ID int > Name string > Skills []string > Relationship map[string]string > Identification Identification > } > > var sJsonBlob = []byte(`{"錯誤":"雜訊","Name":"人員名稱","Skills":["玩","運動"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"JPhone":"cc@cc.com","JEmail":false}}`) > var stUser User > err = json.Unmarshal(sJsonBlob, &stUser) > if err != nil { > fmt.Println("error:", err) > } > fmt.Printf("%+v", stUser) > fmt.Println() > // error: json: cannot unmarshal bool into Go struct field Identification.JEmail of type string //該錯誤為 "JEmail":false 所產生 > // {ID:0 Name:人員名稱 Skills:[玩 運動] Relationship:map[Dad:Hulk Mon:Natasha] Identification:{Phone:cc@cc.com Email:}} > // 多餘的切片元素將會被json.Unmarshal棄置 > } > > ``` ### Go : 注入(inject)(github)應用: > ``go get github.com/codegangsta/inject`` > ```go= > package main > import ( > "fmt" > > "github.com/codegangsta/inject" > ) > > /* > github.com/codegangsta/inject 利用反射(reflect)包所設計, > 可將自動將變數注入到func和struct中,實現變數自動排列輸入 > > */ > > type TY_S1 interface{} > type TY_S2 interface{} > > type Ty_Staff struct { > Name string `inject` > Company TY_S1 `inject` > Level TY_S2 `inject` > Age int `inject` > } > > func FC_PrintData(vs_name string, if_company TY_S1, if_level TY_S2, vi_age int) { > fmt.Printf("name=%s, company=%s, level=%s, age=%d\n", vs_name, if_company, if_level, vi_age) > } > > func main() { > > InjectNew := inject.New() > InjectNew.Map("姓名") > InjectNew.MapTo("公司名稱", (*TY_S1)(nil)) > InjectNew.MapTo("職稱", (*TY_S2)(nil)) > InjectNew.Map(23) > InjectNew.Invoke(FC_PrintData) //name=姓名, company=公司名稱, level=職稱, age=99 > > st_Staff := Ty_Staff{} > InjectNew.Apply(&st_Staff) > fmt.Printf("%v\n", st_Staff) //{XX 公司名稱 職稱 99} > > println() > ///////////////////////////////////////////////////////////////////////////////////////////////////////// > > InjectNewE := inject.New() > InjectNewE.Map("姓名") > InjectNewE.MapTo("公司名稱", (*TY_S1)(nil)) > InjectNewE.MapTo("職稱", (*TY_S2)(nil)) > InjectNewE.Map(23) > > InjectNewE.Map("覆寫姓名") > InjectNewE.MapTo("覆寫公司名稱", (*TY_S1)(nil)) > InjectNewE.MapTo("覆寫職稱", (*TY_S2)(nil)) > InjectNewE.Map(99) > InjectNewE.Map(11.11) //多餘資料 > > InjectNewE.Invoke(FC_PrintData) //name=覆寫姓名, company=覆寫公司名稱, level=覆寫職稱, age=99 > > st_StaffE := Ty_Staff{} > InjectNewE.Apply(&st_StaffE) > fmt.Printf("%v\n", st_StaffE) //{覆寫姓名 覆寫公司名稱 覆寫職稱 99} > > } > ``` ### Go : rpc應用: > ==server.go== > ```go= > package main > > import ( > "log" > "net" > "net/http" > "net/rpc" > ) > > type Item struct { > Title string > Body string > } > > type API int > > var database []Item > > func (a *API) GetDB(empty string, reply *[]Item) error { > *reply = database > return nil > } > > func (a *API) GetByName(title string, reply *Item) error { > var getItem Item > > for _, val := range database { > if val.Title == title { > getItem = val > } > } > > *reply = getItem > > return nil > } > > func (a *API) AddItem(item Item, reply *Item) error { > database = append(database, item) > *reply = item > return nil > } > > func (a *API) EditItem(item Item, reply *Item) error { > var changed Item > > for idx, val := range database { > if val.Title == item.Title { > database[idx] = Item{item.Title, item.Body} > changed = database[idx] > } > } > > *reply = changed > return nil > } > > func (a *API) DeleteItem(item Item, reply *Item) error { > var del Item > > for idx, val := range database { > if val.Title == item.Title && val.Body == item.Body { > database = append(database[:idx], database[idx+1:]...) > del = item > break > } > } > > *reply = del > return nil > } > > func main() { > api := new(API) > err := rpc.Register(api) > if err != nil { > log.Fatal("error registering API", err) > } > > rpc.HandleHTTP() > > listener, err := net.Listen("tcp", ":4040") > > if err != nil { > log.Fatal("Listener error", err) > } > log.Printf("serving rpc on port %d", 4040) > http.Serve(listener, nil) > > if err != nil { > log.Fatal("error serving: ", err) > } > > > } > ``` > > ==client.go== > ```go= > package main > > import ( > "fmt" > "log" > "net/rpc" > ) > > type Item struct { > Title string > Body string > } > > func main() { > var reply Item > var db []Item > > client, err := rpc.DialHTTP("tcp", "localhost:4040") > > if err != nil { > log.Fatal("Connection error: ", err) > } > > a := Item{"First", "A first item"} > b := Item{"Second", "A second item"} > c := Item{"Third", "A third item"} > > client.Call("API.AddItem", a, &reply) > client.Call("API.AddItem", b, &reply) > client.Call("API.AddItem", c, &reply) > client.Call("API.GetDB", "", &db) > > fmt.Println("Database: ", db) > > client.Call("API.EditItem", Item{"Second", "A new second item"}, &reply) > > client.Call("API.DeleteItem", c, &reply) > client.Call("API.GetDB", "", &db) > fmt.Println("Database: ", db) > > client.Call("API.GetByName", "First", &reply) > fmt.Println("first item: ", reply) > > } > > ``` ### Go : Protobuf (proto3)應用: > > [參考資料](https://yami.io/protobuf/) > [變數型別(proto3)](https://developers.google.com/protocol-buffers/docs/proto3) > > ```bash > ##Golang proto套件安裝 > go get -u github.com/golang/protobuf/{proto,protoc-gen-go} > ``` > > ```bash > # Ubuntu安裝 > curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.10.1/protoc-3.10.1-linux-x86_64.zip > su > unzip protoc-3.10.1-linux-x86_64.zip -d protoc3 > > # 移動 > mv protoc3/bin/* /usr/local/bin/ > mv protoc3/include/* /usr/local/include/ > > # 修改權限 > chown [user] /usr/local/bin/protoc > chown -R [user] /usr/local/include/google > ``` > > ```bash > ## windows安裝protoc後必須另外將protoc.exe環境變數%Path%內 > ## protoc-gen-go.exe必須與protoc.exe在同一資料夾 > copy protoc-gen-go.exe %Path% > ``` > Golang範例: > > ``./person.proto``: > ``` go > syntax="proto3"; > > package main; > > message Person { > string name = 1; > int32 age = 2; > } > ``` > > ```bash > ## 將person.proto生成 person.pb.go > protoc --go_out=. person.proto > ``` > > ``./person.pb.go``: > ```go= > // Code generated by protoc-gen-go. DO NOT EDIT. > // source: person.proto > > package main > > import ( > fmt "fmt" > math "math" > > proto "github.com/golang/protobuf/proto" > ) > > // Reference imports to suppress errors if they are not otherwise used. > var _ = proto.Marshal > var _ = fmt.Errorf > var _ = math.Inf > > // This is a compile-time assertion to ensure that this generated file > // is compatible with the proto package it is being compiled against. > // A compilation error at this line likely means your copy of the > // proto package needs to be updated. > const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package > > type Person struct { > Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"Name,omitempty"` > Age int32 `protobuf:"varint,3,opt,name=age,proto3" json:"age,omitempty"` > XXX_NoUnkeyedLiteral struct{} `json:"-"` > XXX_unrecognized []byte `json:"-"` > XXX_sizecache int32 `json:"-"` > } > > func (m *Person) Reset() { *m = Person{} } > func (m *Person) String() string { return proto.CompactTextString(m) } > func (*Person) ProtoMessage() {} > func (*Person) Descriptor() ([]byte, []int) { > return fileDescriptor_4c9e10cf24b1156d, []int{0} > } > > func (m *Person) XXX_Unmarshal(b []byte) error { > return xxx_messageInfo_Person.Unmarshal(m, b) > } > func (m *Person) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { > return xxx_messageInfo_Person.Marshal(b, m, deterministic) > } > func (m *Person) XXX_Merge(src proto.Message) { > xxx_messageInfo_Person.Merge(m, src) > } > func (m *Person) XXX_Size() int { > return xxx_messageInfo_Person.Size(m) > } > func (m *Person) XXX_DiscardUnknown() { > xxx_messageInfo_Person.DiscardUnknown(m) > } > > var xxx_messageInfo_Person proto.InternalMessageInfo > > func (m *Person) GetName() string { > if m != nil { > return m.Name > } > return "" > } > > func (m *Person) GetAge() int32 { > if m != nil { > return m.Age > } > return 0 > } > > func init() { > proto.RegisterType((*Person)(nil), "main.Person") > } > > func init() { proto.RegisterFile("person.proto", fileDescriptor_4c9e10cf24b1156d) } > > var fileDescriptor_4c9e10cf24b1156d = []byte{ > // 88 bytes of a gzipped FileDescriptorProto > 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x48, 0x2d, 0x2a, > 0xce, 0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xc9, 0x4d, 0xcc, 0xcc, 0x53, 0xd2, > 0xe3, 0x62, 0x0b, 0x00, 0x8b, 0x0a, 0x09, 0x71, 0xb1, 0xf8, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x29, > 0x30, 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x02, 0x5c, 0xcc, 0x89, 0xe9, 0xa9, 0x12, 0xcc, 0x0a, > 0x8c, 0x1a, 0xac, 0x41, 0x20, 0x66, 0x12, 0x1b, 0x58, 0xb3, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, > 0xf8, 0xbc, 0xb8, 0xfe, 0x4c, 0x00, 0x00, 0x00, > } > > > ``` > > ``./main.go``: > ```go > package main > > import ( > "fmt" > > "github.com/golang/protobuf/proto" > ) > > func main() { > > elliot := &Person{ > Name: "Elliot", > Age: 24, > } > > sl_ProtobufExample, err := proto.Marshal(elliot) > if err != nil { > fmt.Println("marshaling error: ", err) > } > fmt.Printf("%s\n", sl_ProtobufExample) //?Elliot > > st_UnProtoExample := &Person{} > err = proto.Unmarshal(sl_ProtobufExample, st_UnProtoExample) > if err != nil { > fmt.Println("unmarshaling error: ", err) > } > > fmt.Println(st_UnProtoExample) //name:"Elliot" age:24 > > } > > ``` > ### Go : 檔案系統操作: > ```go= > package main > > import ( > "bufio" > "errors" > "io" > "io/ioutil" > "net/http" > "os" > "strconv" > ) > > // os.O_WRONLY: 只寫 > // os.O_CREATE: 創建文件(如果文件不存在) > // os.O_RDONLY: 只讀 > // os.O_RDWR: 讀寫皆可 > // os.O_APPEND: 尾部加入 > // os.O_TRUNC: 清空(文件存在情況下) > // 第三個參數設置權限控制 > > > > func fc_GetPWD() string { > vs_WorkingDir, _ := os.Getwd() > return vs_WorkingDir > } > > func fc_SetPWD(FilePathInput string) error { > err := os.Chdir(FilePathInput) > return err > } > > func fc_GetEnv(EnvVarName string) (EnvVarValue string) { > return os.Getenv(EnvVarName) > } > > func fc_GetAllEnv(EnvVarName string) (AllEnvVarValues []string) { > return os.Environ() > } > > func fc_GetPathList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > FolderList = append(FolderList, value.Name()) > } > return FolderList, nil > } > > func fc_GetFolderList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > if value.IsDir(){ > FolderList = append(FolderList, value.Name()) > } > } > return FolderList, nil > } > > func fc_GetFileList(FilePathInput string) (FolderList []string, err error) { > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return FolderList, err > } > > ty_FileInfos, err := pty_OpenFile.Readdir(-1) > pty_OpenFile.Close() > if err != nil { > return FolderList, err > } > for _, value := range ty_FileInfos { > if !value.IsDir(){ > FolderList = append(FolderList, value.Name()) > } > } > return FolderList, nil > } > > func fc_FileMove(FilePathInput, FilePathOutput string) error { > return os.Rename(FilePathInput, FilePathOutput) > } > > func fc_SetEnv(EnvVarName, EnvVarValue string) error { > return os.Setenv(EnvVarName, EnvVarValue) > } > > func fc_IsFileModeCode(vs_chmod string) bool { > if len(vs_chmod) == 3 || len(vs_chmod) == 4 { > _, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) > if err_chmodCheck == nil { > for _, value := range vs_chmod { > if value == '8' || value == '9' { > return false > } > } > return true > } > } > return false > } > > func fc_FileModeEnCode(vs_chmod string) (vs_ModeCodestring string, err error) { > switch len(vs_chmod) { > case 1: //r、w表示同時適用OWNER(Windows,Unix) > switch vs_chmod { > case "r": > return "0200", nil > case "w": > return "0400", nil > } > case 2: //rw兩字表示同時適用OWNER(Windows,Unix) > if vs_chmod == "rx" || vs_chmod == "xr" { > return "0200", nil > } else if vs_chmod == "wx" || vs_chmod == "xw" { > return "0400", nil > } else if vs_chmod == "rw" || vs_chmod == "wr" { > return "0600", nil > } > case 3: //rwx三字表示同時適用OWNER(Windows,Unix),777三數字僅適用Unix > switch vs_chmod { > case "rwx", "rxw", "xrw", "xwr", "wrx", "wxr": > return "0700", nil > default: > if fc_IsFileModeCode(vs_chmod) { > return "0" + vs_chmod, nil > } > } > case 4: > if fc_IsFileModeCode(vs_chmod) { > return vs_chmod, nil > } > case 9: > var vu_ower, vu_group, vu_others, vu_sum uint64 > for index, value := range vs_chmod { > switch value { > case 'r': > vu_sum = vu_sum + 4 > case 'w': > vu_sum = vu_sum + 2 > case 'x': > vu_sum = vu_sum + 1 > case '-': > continue > default: > return "", errors.New("Bad chmod input") > } > > switch index { > case 2: > vu_ower = vu_sum > vu_sum = 0 > case 5: > vu_group = vu_sum > vu_sum = 0 > case 8: > vu_others = vu_sum > case 9: > return "", errors.New("Bad chmod input") > } > } > > if vu_ower > 7 || vu_group > 7 || vu_others > 7 { > return "", errors.New("Bad chmod input") > } else { > return "0" + strconv.FormatUint(vu_ower, 10) + strconv.FormatUint(vu_group, 10) + strconv.FormatUint(vu_others, 10), nil > } > > } > return "", errors.New("Bad chmod input") > } > > func fc_IsExist(FilePathInput string) bool { > if _, err := os.Stat(FilePathInput); os.IsExist(err) { > return false > } > return true > } > > func fc_IsNotExist(FilePathInput string) bool { > if _, err := os.Stat(FilePathInput); os.IsNotExist(err) { > return true > } > return false > } > > func fc_CreatFile(FilePathInput string) error { > _, err := os.Create(FilePathInput) //666 > return err > } > > func fc_CreatFolder(FilePathInput, vs_chmod string) error { > var err error > if vs_chmod == "" { > err = os.MkdirAll(FilePathInput, 0777) > return err > } > > vu_chmodNum, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) > if err_chmodCheck != nil { > err = os.MkdirAll(FilePathInput, 0777) > } else { > err = os.MkdirAll(FilePathInput, os.FileMode(vu_chmodNum)) > } > > return err > } > > func fc_RemovePath(FilePathInput string) error { > err := os.RemoveAll(FilePathInput) > return err > } > > func fc_RemoveFile(FilePathInput string) error { > ty_FileStat, err := os.Stat(FilePathInput) > if !ty_FileStat.IsDir() { > err = os.Remove(FilePathInput) > return err > } else { > return errors.New("It's a Folder not File") > } > } > > func fc_RemoveFolder(FilePathInput string) error { > ty_FileStat, err := os.Stat(FilePathInput) > if ty_FileStat.IsDir() { > err = os.Remove(FilePathInput) > return err > } else { > return errors.New("It's a File not Empty-Folder") > } > } > > func fc_ReadFile(FilePathInput string) (string, error) { > > sl_Output, err := ioutil.ReadFile(FilePathInput) > if err != nil { > return "", err > } else { > return string(sl_Output), nil > } > > } > > func fc_ReadBufFile(FilePathInput string, BufSize int64) (string, error) { > > pty_OpenFile, err := os.Open(FilePathInput) > if err != nil { > return "", err > } > defer pty_OpenFile.Close() > > pty_BufReader := bufio.NewReader(pty_OpenFile) > sl_Output := make([]byte, BufSize) > > _, err = pty_BufReader.Read(sl_Output) > if err != nil { > return "", err > } else { > return string(sl_Output), nil > } > > } > > func fc_ClearFile(FilePathInput string) error { > > _, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_TRUNC, 0222) > return err > } > > func fc_AppendFile(FilePathInput string, WriteString string) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > pty_NewWriter := bufio.NewWriter(pty_OpenFile) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_AppendBufFile(FilePathInput string, WriteString string, vi_Bufsize int) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 > pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_WriteNewFile(FilePathInput string, WriteString string) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > pty_NewWriter := bufio.NewWriter(pty_OpenFile) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_WriteBufNewFile(FilePathInput string, WriteString string, vi_Bufsize int) error { > pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) > if err != nil { > return err > } > defer pty_OpenFile.Close() > > //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 > pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) > > //將檔案寫入快取 > if _, err = pty_NewWriter.WriteString(WriteString); err != nil { > return err > } > //從快取寫入到檔案中 > if err = pty_NewWriter.Flush(); err != nil { > return err > } else { > return nil > } > } > > func fc_UrlDownload(SavePathInput string, UrlInput string) error { > > // Get the data > pty_HttpRESP, err := http.Get(UrlInput) > if err != nil { > return err > } > defer pty_HttpRESP.Body.Close() > > // Create the file > pty_FileOut, err := os.Create(SavePathInput) > if err != nil { > return err > } > defer pty_FileOut.Close() > > // Write the body to file > _, err = io.Copy(pty_FileOut, pty_HttpRESP.Body) > return err > } > > > ``` ### Go : try-catch 實作: > ```go= > package main > > import "fmt" > > func main() { > > someVar := "----- start test -----" > emptyVar := "" > > Catcher(func(panicErr interface{}) { > > fmt.Printf("something error : \n%v\n", panicErr) > > }, func() { > > fmt.Println(someVar) > //panic("自定義錯誤") > fmt.Println(emptyVar[0]) > > }) > > fmt.Println("----- still running -----") > > // Try func active > // ----- start test ----- > // something error : > // runtime error: index out of range > // ----- still running ----- > } > > func Catcher(handler func(interface{}), run func()) { > defer func() { > if err := recover(); err != nil { > handler(err) > } > }() > > fmt.Println("Try func active") > run() > } > > ``` ### Go : Google Sheet API對接實作: > ```go= > package main > > import ( > "bytes" > "encoding/json" > "errors" > "fmt" > "io/ioutil" > "log" > "os" > > "golang.org/x/net/context" > "golang.org/x/oauth2" > "golang.org/x/oauth2/google" > "google.golang.org/api/sheets/v4" > ) > > const ( > googleAppCredentials = "./license/credentials.json" > googleAccountToken = "./license/token.json" > googleErrorTitle = "Google Sheet API 預期錯誤" > ) > > func main() { > > credentials, err := ioutil.ReadFile(googleAppCredentials) > if err != nil { > log.Fatalf("Unable to read client secret file: %v\n", err) > //https://developers.google.com/sheets/api/quickstart/go 需要開啟獲取app 使用google api許可 > } > > token, err := ioutil.ReadFile(googleAccountToken) > if err != nil { > log.Printf("Unable to read client secret file: %v\n", err) > > var getGSService GoogleSheet > token, err = getGSService.CreatAccTokenFromWeb(credentials, googleAccountToken, false) > if err != nil { > log.Fatalf("Unable to save oauth token: \n %s (%v)\n", credentials, err) > } > > } else { > var js map[string]interface{} //空interface可以容許json格式多餘換行,較人性化 > if json.Unmarshal(token, &js) != nil { > log.Fatalf("INVALID json: %v\n%v", err, token) > //log.Printf("INVALID json: %v\n%v\n進行重新獲取Token>>>>>\n", err, token) > } > } > > // var gs1 GoogleSheet > // gs1.SetService(credentials, token, "1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", false) > > // values, err := gs1.Read("Table!A2:B9") > // if err != nil { > // log.Fatalf("Unable to retrieve data from sheet: %v\n", err) > // } > // fmt.Println(values) > > // var writeValues [][]interface{} > // xx := []interface{}{ > // 0, 1, 2, 3, 4, 5, > // 10, 11, 12, 13, 14, 15, > // 20, 21, 22, 23, 24, 25, > // 30, 31, 32, 33, 34, 35, > // } > // writeValues = append(writeValues, xx) > > // err = gs1.Clear("Table!C8:C9") > // if err != nil { > // log.Fatalf("Unable to retrieve data from sheet: %v\n", err) > // } > > // var updateValues [][]interface{} > // row := []interface{}{"BBB", "CCC", "DDD"} > // updateValues = append(updateValues, row) > // err = gs1.Update("Table!C3", updateValues) > // if err != nil { > // log.Fatal(err) > // } > > var gs1 GoogleSheet > gs1.SetService(credentials, token, "1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", false) > //gs1.SheetCopy("1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", 210732483, "161anr6Guf9Mdmcz--10bb9G62aEEgbjQGJjzJXMqVRY") > gs1.CopyFromSheet("161anr6Guf9Mdmcz--10bb9G62aEEgbjQGJjzJXMqVRY", 2014644818, "test") > > //fmt.Println(gs1.GetSheetGID("「Monthly Rates」的副本")) > //gs1.SheetRename(1791097333,"測試!!!!!!!!!!!!!!") > > } > > type GoogleSheet struct { > Srv *sheets.Service > Ctx context.Context > AppCredentials []byte //程式本身許可license > AccToken []byte //google帳戶license > SpreadSheetID string //預設google Sheet ID (由網址url取得) > } > > //獲取google API 控制權限設定(綁定method) > func (gs *GoogleSheet) getGoogleAPIConfig(appCredentials []byte, setReadOnly bool) (config *oauth2.Config, err error) { > // https://developers.google.com/sheets/api/guides/authorizing 選擇api控制google帳號權限 > // https://www.googleapis.com/auth/spreadsheets.readonly Allows read-only access to the user's sheets and their properties. > // https://www.googleapis.com/auth/spreadsheets Allows read/write access to the user's sheets and their properties. > // https://www.googleapis.com/auth/drive.readonly Allows read-only access to the user's file metadata and file content. > // https://www.googleapis.com/auth/drive.file Per-file access to files created or opened by the app. > // https://www.googleapis.com/auth/drive > var scopeUrl string > if setReadOnly { > scopeUrl = sheets.SpreadsheetsReadonlyScope > } else { > scopeUrl = sheets.SpreadsheetsScope > } > > config, err = google.ConfigFromJSON(appCredentials, scopeUrl) > if err != nil { > //log.Printf("Unable to parse client secret file to config: %v\n", err) > return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") > } > > return config, nil > } > > func (gs *GoogleSheet) GetSheetGID(sheetName string) (int64, error) { > > sheetService, err := gs.Srv.Spreadsheets.Get(gs.SpreadSheetID).Do() > if err != nil { > return 0, errors.New(googleErrorTitle + ": 「" + gs.SpreadSheetID + "」 該SheetID不存在,請檢查網址或AccountToken權限!") > } > > for _, sheet := range sheetService.Sheets { > if sheet.Properties.Title == sheetName { > return sheet.Properties.SheetId, nil > } > } > return 0, errors.New(googleErrorTitle + ": 「" + sheetName + "」 該Sheet Name不存在,請檢查Sheet內容!") > } > > //建立Google帳戶Token File(需要瀏覽器手動操作) > func (gs *GoogleSheet) CreatAccTokenFromWeb(appCredentials []byte, accTokenFilePath string, setReadOnly bool) (accToken []byte, err error) { > > config, err := gs.getGoogleAPIConfig(appCredentials, setReadOnly) > if err != nil { > //log.Printf("Unable to parse client secret file to config: %v\n", err) > return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") > } > > // Request a token from the web, then returns the retrieved token. > authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline) > fmt.Printf("\n%v\n↑請使用瀏覽器設定你的Google帳戶,並貼入你的token authorization code ↑\n", authURL) > var authCode string > if _, err := fmt.Scan(&authCode); err != nil { > //log.Fatalf("Unable to read authorization code: %v", err) > return nil, err > } > > tok, err := config.Exchange(context.TODO(), authCode) > if err != nil { > //log.Fatalf("Unable to retrieve token from web: %v", err) > return nil, err > } > > // Saves a token to a file path. > fmt.Printf("已將token authorization code存入 : %s\n", accTokenFilePath) > accTokenFileWrite, err := os.OpenFile(accTokenFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) > if err != nil { > //log.Fatalf("Unable to cache oauth token: %v", err) > return nil, errors.New(googleErrorTitle + ": 「" + accTokenFilePath + "」AccountToken儲存失敗!") > } > defer accTokenFileWrite.Close() > json.NewEncoder(accTokenFileWrite).Encode(tok) > > gs.Ctx = context.Background() > client := config.Client(gs.Ctx, tok) > _, err = sheets.New(client) > if err != nil { > //log.Fatalf("Unable to retrieve Sheets client: %v", err) > return nil, err > } > > token, err := ioutil.ReadFile(accTokenFilePath) > if err != nil { > //log.Fatalf("Unable to save oauth token: %v", err) > return nil, err > } > > return []byte(token), nil > } > > //設置Google Sheet連結服務 > func (gs *GoogleSheet) SetService(appCredentials []byte, accToken []byte, spreadSheetID string, setReadOnly bool) (*sheets.Service, error) { > > gs.AppCredentials = appCredentials > gs.AccToken = accToken > gs.SpreadSheetID = spreadSheetID //預先存入docs網址方便日後存取 > > config, err := gs.getGoogleAPIConfig(appCredentials, setReadOnly) > if err != nil { > // log.Printf("Unable to parse client secret file to config: %v\n", err) > return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") > } > > tok := &oauth2.Token{} > err = json.NewDecoder(bytes.NewReader(gs.AccToken)).Decode(tok) > if err != nil { > //log.Fatalf("Unable to cache oauth token: %v", err) > return nil, err > } > client := config.Client(context.Background(), tok) > > gs.Srv, err = sheets.New(client) > if err != nil { > //log.Printf("Unable to retrieve Sheets client: %v\n", err) > return nil, err > } > > return gs.Srv, nil > > } > > //獲取sheet中的數值 > func (gs *GoogleSheet) SheetRead(readRange string) ([][]interface{}, error) { > resp, err := gs.Srv.Spreadsheets.Values.Get(gs.SpreadSheetID, readRange).Do() > > if err != nil { > return nil, err > } > > return resp.Values, err > } > > //寫入sheet中的數值 > func (gs *GoogleSheet) SheetWrite(writeRange string, values [][]interface{}) error { > valueInputOption := "RAW" > requestBody := &sheets.ValueRange{ > MajorDimension: "ROWS", > Values: values, > } > > _, err := gs.Srv.Spreadsheets.Values.Append(gs.SpreadSheetID, writeRange, requestBody).ValueInputOption(valueInputOption).Do() > > return err > } > > //改變sheet中的數值 > func (gs *GoogleSheet) SheetUpdate(updateRange string, updateValues [][]interface{}) error { > valueInputOption := "RAW" > requestBody := &sheets.ValueRange{ > MajorDimension: "ROWS", > Values: updateValues, > } > > _, err := gs.Srv.Spreadsheets.Values.Update(gs.SpreadSheetID, updateRange, requestBody).ValueInputOption(valueInputOption).Do() > > return err > } > > //清除sheet中的數值 > func (gs *GoogleSheet) SheetClear(clearRange string) error { > // rb has type *ClearValuesRequest > requestBody := &sheets.ClearValuesRequest{} > > _, err := gs.Srv.Spreadsheets.Values.Clear(gs.SpreadSheetID, clearRange, requestBody).Do() > > return err > } > > //操作兩Google Sheet 間作sheet複製(需要自行設置權限,並取得Sheet的gid) > func (gs *GoogleSheet) CopyBetweenSheet(sourceSheetID string, sourceSheetGID int64, destSheetID string) (resp *sheets.SheetProperties, err error) { > > requestBody := &sheets.CopySheetToAnotherSpreadsheetRequest{ > DestinationSpreadsheetId: destSheetID, > } > > resp, err = gs.Srv.Spreadsheets.Sheets.CopyTo(sourceSheetID, sourceSheetGID, requestBody).Context(gs.Ctx).Do() > > return resp, err > } > > //選擇sheetGID 並重新命名 > func (gs *GoogleSheet) SheetGIDRename(sheetGID int64, newName string) (resp *sheets.BatchUpdateSpreadsheetResponse, err error) { > > requestBody := &sheets.BatchUpdateSpreadsheetRequest{ > Requests: []*sheets.Request{&sheets.Request{ > UpdateSheetProperties: &sheets.UpdateSheetPropertiesRequest{ > Properties: &sheets.SheetProperties{ > SheetId: sheetGID, > Title: newName, > }, > Fields: "title", > }, > }}, > } > > resp, err = gs.Srv.Spreadsheets.BatchUpdate(gs.SpreadSheetID, requestBody).Context(gs.Ctx).Do() > return resp, err > } > > //複製外部sheet到現在工作的Google Sheet(需要自行設置權限,並取得Sheet的gid) > func (gs *GoogleSheet) CopyFromSheet(sourceSheetID string, sourceSheetGID int64, newName string) (resp *sheets.SheetProperties, err error) { > > requestBody := &sheets.CopySheetToAnotherSpreadsheetRequest{ > DestinationSpreadsheetId: gs.SpreadSheetID, > } > > resp, err = gs.Srv.Spreadsheets.Sheets.CopyTo(sourceSheetID, sourceSheetGID, requestBody).Context(gs.Ctx).Do() > if newName != "" && err == nil { > _, err2 := gs.SheetGIDRename(resp.SheetId, newName) > if err2 != nil { > err = err2 > } > } > > return resp, err > } > > ``` ### Go : Socket實作: > ##### ==Server端:== > ```go= > package main > import ( > "fmt" > "log" > "net" > "os" > "time" > ) > > const buffSize = 1024 > func main() { > > //建立socket,監聽埠 > listenPort := ":51680" > netListen, err := net.Listen("tcp", listenPort) > if err != nil { > log.Printf("listen tcp '%v' fail > '%v'\n", listenPort, err) > os.Exit(1) > } > defer netListen.Close() > > log.Println("Waiting for clients") > var clientList = make(map[*net.Conn]struct{}) > go func() { //監聽採用無限制迴圈 > for { > conn, err := netListen.Accept() > if err != nil { > continue > } > > clientIP := conn.RemoteAddr().String() > log.Println(clientIP, " tcp connect success") > buffer := make([]byte, buffSize) //超過緩存範圍訊息將被斷行打印 > go func() { //每個客戶端開goroutine > for { > clientList[&conn] = struct{}{} //struct不占記憶體空間 > endChr, err := conn.Read(buffer) //阻塞式,當無client連接時會進行等待 > if err != nil { > log.Println(clientIP, " connection error: ", err) > delete(clientList, &conn) > break > } > > switch string(buffer[:endChr]) { > case "bye": //關閉客戶端 > conn.Write([]byte("Bye bye!")) > delete(clientList, &conn) //移除廣播清單 > return //關閉goroutine > default: //接收客戶端訊息 > log.Println(clientIP, "receive data string:") > } > } > return > }() > > } > }() > > var sendMsg string > for { //廣播給所有清單內的客戶端 > fmt.Scanln(&sendMsg) > for client, _ := range clientList { > conn := *client > _, err := conn.Write([]byte(sendMsg)) > if err != nil { > log.Println("廣播 fail : ", conn.RemoteAddr()) > continue //監聽程序會負責移除斷線或異常的客戶端 > } > } > log.Printf("廣播 : %s", sendMsg) > time.Sleep(1 * time.Second) > } > } > ``` > > ##### ==Client端:== > ```go= > package main > import ( > "fmt" > "log" > "net" > "time" > ) > > const buffSize = 1024 > > func main(){ > > socketAddr := "localhost:51680" > var err error > var socketServer *net.Conn //socket server公用控制器 > go func(addr string) { > var conn net.Conn > buff := make([]byte, buffSize) > for { > if socketServer == nil { > conn, err = net.Dial("tcp", addr) //與server進行連線 > if err != nil { > log.Printf("Reconnect error:%v\n", err) > socketServer = nil > time.Sleep(1 * time.Second) > continue > } else { > socketServer = &conn > defer conn.Close() > log.Printf("Suecess to connect socket > '%v'\n", addr) > } > } > > endChr, err := conn.Read(buff) //接收server訊息 > if err != nil { > log.Println("Receive fail!") > socketServer = nil > continue > } > log.Printf("Received from server : %s", buff[:endChr]) > } > }(socketAddr) > > var sendMsg string > for { > fmt.Scanln(&sendMsg) > conn := *socketServer //指向公用socket server > _,err :=conn.Write([]byte(sendMsg)) > if err !=nil{ > log.Println("Sent fail !") > socketServer = nil > continue //若發送失敗接收者負責重連 > } > log.Printf("Send: %s", sendMsg) > time.Sleep(1 * time.Second) > } > } > > ``` ### Go : socket.io實作: > ##### ==Server端:== > ```go= > package main > > import ( > "fmt" > "log" > "net/http" > "time" > > socketio "github.com/googollee/go-socket.io" > ) > > const broadcastKey = "broadcast" > const clientKey = "client message" > > func main() { > server := socketio.NewServer(nil) > > var Clients = make(map[string]socketio.Conn) //連線中的Client清單 > server.OnConnect("/", func(conn socketio.Conn) error { > conn.SetContext("") > log.Printf("connected: %v (url:'%v' LocalAddr:'%v' RemoteAddr:'%v' RemoteHeader:'%v')", conn.ID(),conn.URL(),conn.LocalAddr(),conn.RemoteAddr(),conn.RemoteHeader()) > Clients[conn.ID()] = conn > return nil > }) > > server.OnDisconnect("/", func(conn socketio.Conn, reason string) { > delete(Clients, conn.ID()) //清除廣播清單 > log.Printf("%v closed : %v\n", conn.ID(), reason) > }) > > server.OnError("/", func(conn socketio.Conn, err error) { > log.Println("meet error:", err) //錯誤捕捉 > }) > > server.OnEvent("/", clientKey, func(conn socketio.Conn, msg string) { > if msg != "bye" { //當客戶端發送bye則將客戶端關閉 > log.Printf("get from %v : %v \n", conn.ID(), msg) > conn.Emit(clientKey, fmt.Sprintf("We have received your message : '%v'", msg)) //回傳給客戶端 > } else { > conn.Emit("bye !") > log.Printf("force close client %v", conn.ID()) > conn.Close() > } > }) > > go func(server *socketio.Server) { > for { > for index, value := range Clients { > value.Emit(broadcastKey, "廣播") > log.Printf("對%v 發出了廣播\n", index) > } > time.Sleep(5 * time.Second) > } > }(server) > > go server.Serve() > defer server.Close() > > http.Handle("/socket.io/", server) > http.Handle("/", http.FileServer(http.Dir("./asset"))) > log.Println("Serving at localhost:51680...") > log.Fatal(http.ListenAndServe(":51680", nil)) > } > ``` > ##### ==Client端:== > ```go= > package main > > import ( > "fmt" > "log" > "time" > > socketIoClient "github.com/mofadeyunduo/go-socket.io-client" > ) > > const broadcastKey = "broadcast" > const clientKey = "client message" > > func main() { > > // options 為選用功能 > // options := &socketIoClient.Options{ > // Transport: "websocket", > // Query: make(map[string]string), > // } > // options.Query["user"] = "user" > // options.Query["pwd"] = "pass" > > var socketClient *socketIoClient.Client //socket server 連線控制器 > socketHost := "http://localhost:51680" > socketOptions := &socketIoClient.Options{} > go func(client *socketIoClient.Client, uri string, opts *socketIoClient.Options) { //由於socket斷線後不會有任何提示,所以需要自行檢測與重連 > for { > if client == nil || client.Emit("ping", "") != nil { > var err error > client, err = socketIoClient.NewClient(uri, socketOptions) //與socket server 連線 > if err != nil { > client = nil //清空連線 > log.Printf("Reconnect error:%v\n", err) > } else { > socketClient = client > log.Printf("suecess to connect socket.io > '%v'\n", socketHost) > > client.On(broadcastKey, func(msg string) { //開啟監聽Server端廣播 > log.Printf("got broadcast: '%v'\n", msg) > }) > > client.On(clientKey, func(msg string) { //開啟監聽Server端傳訊 > log.Printf("got message: '%v'\n", msg) > }) > } > } > > time.Sleep(1 * time.Second) //每秒重新連線,並重新監聽 > } > }(socketClient, socketHost, socketOptions) > > var sendMsg string > for { > fmt.Scanln(&sendMsg) > if socketClient.Emit(clientKey, sendMsg) == nil { > log.Printf("sent : '%v'", sendMsg) > } else { > log.Println("sent fail !") > } > time.Sleep(1 * time.Second) //每秒重新連線,並重新監聽 > } > } > >

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully