發表文章

目前顯示的是 2018的文章

[Go] Golang 相對路徑以及沒有使用gofmt的衍生問題

今天遇到一個奇特的問題 在我將專案內import 的相對路徑改成絕對路徑的時候,竟然出現了一些不知道從哪裡來的物件名稱。 想當然爾,編譯是不會過關的,但前人的編譯確可以順利通過。 肇事原因,就是前人的兩個做法所影響 1. 用相對路徑去import package 2. 沒有用gofmt 情境如下: "../../kernel/api" 這個其實是幫你找到一個叫做『api 』的資料夾位置 如果我在『api 』這個資料放的package 名稱叫做myservice 這樣是可以過關的,而且你在import "../../kernel/api" 的檔案內 可以用 myservice.XXXX ,這個package內的東西! (原則上package的命名和外面的資料夾名稱應該一樣,這個是不好示範) 目錄如下 kernel - api - send_request.go send_request.go 檔案內容 package myservice func begin(){ // todo function implement } 某個有使用send_request.go檔案的內容 package logic import "../../kernel/api" func buildLogic() { myservice.begin() } 我看到就是類似myservice.的東西,滿臉的問號它是從哪打來的? 會有這樣的結果,也是因為沒用gofmt 如果有用gofmt,看到未使用的 "../../kernel/api" 早就被砍掉了,因為裡面沒有地方是用api開頭。 挖屋..... 當然可以的話,還是希望大家都能用絕對路經(專案名稱開頭),和gofmt輔助格式整理。 Created Date : 2018/09/28 Last Updated Date : 2018/09/28

[Redis] [Go] Send 不加 MULTI 會怎麼樣

圖片
做redis transaction 基本上先放MULTI,再SEND要操作的行為後,最後送出EXEC。 但SEND 本身是在做queue的動作,即使沒有先送MULTI,也是可以成功把做queue的指令丟給redis。 為了弄清楚差異,做了一點實驗,以下搭配GOlang。 實驗一: 說明:         將最後的EXEC註解掉,中間插個DO。 結果:         結果DO以前有寫入redis,DO以後的沒作用。 實驗二: 說明:         根據實驗一的基礎上,但最一開始有用MULTI包起來。 結果:         結果即使中間有DO,但都沒寫入redis(DO也沒寫入?)。 實驗三: 說明:         將實驗二最下面的EXEC註解打開。 結果:         通通寫入redis。 結論:                 如果沒包MULTI,會因為有DO的指令,沒而被一起執行下去。         如果有包MULTI,因為MULTI會認EXEC,而導致中間的DO,被吃掉。         碰到EXEC,不管之前有包幾個MULTI,都會一併執行。 Created Date : 2018/08/16 Last Updated Date : 2018/08/16

[Go] Golang 的 slice 進階know how

之前聽別人分享使用slice 遇到有些坑,但未說明來由。 最近在閱讀 Golang 新手可能会踩的 50 个坑 ( 英文原文 ) 也看到關於slice說明的一些現象,為什麼有些值會無故消失,或者無故被更改,於是好奇花了些時間研究了一下。 下列說明配合source code,這邊就不重複貼了。 my source code on github 先說結論,slice的使用方式是pointer。 slice、map、channel 三者在Golang使用上是操作方式是pointer,不熟悉的話建議先把內容copy起來再操作比較保險。 請參考GO FAQ Why are maps, slices, and channels references while arrays are values? 我自己在寫FAQ的心得文章 有印象。 當下是以為在傳遞function的參數,和接受參數的部分對於 maps, slices, and channels 有這樣的說明,不過現在看來這個也是在講平常assign的使用上。 實驗分為test1() test2() test3()。 test1() 和test2() 把某個slice assign到另外一新的變數,表面上看似有了兩個slice,不過是多了一個新的變數名稱,其實指到相同的slice內容而已。 如果改了其中的內容,兩個slice都會影響到,因為他們是指向同樣的地方。 但若(舊的slice + 新的value) ----> 就會自動產生出新的slice,於是跟舊的slice沒有關係了,各改各的不會受影響。 test3() 將記憶體位置印出來,事實上實驗起來,可以發現每個slice裡面的index皆占了一個記憶體空間,假設有兩個slice,裡面的元素可以指向同樣的地方,也可以分別指到不同的地方 x := append(s, 11) // 只有擴到x,但s還是舊的 fmt.Println("cap(s) =", cap(s), "ptr(s) =", &s[0], "ptr(x) =", &x[0]) fmt.Println("cap(s)

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART4 END

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART4這裡有 Functions and Methods   Control flow Packages and Testing Implementation  Performance Changes from C --Functions and Methods-- Why do T and *T have different method sets? 接收到型態T的對象,有型態T所有的method,但如果是接收到型態*T,則會擁有型態T和型態*T的所有method。 如果interface裡面包含*T,那麼操作的行為會是pointer,如果是T,那操作的行為只能是value的處理方式。 如果是傳value,copy值之後,就跟原本被copy的部分沒關係了。 What happens with closures running as goroutines? func main() { done := make(chan bool) values := []string{"a", "b", "c"} for _, v := range values { go func() { fmt.Println(v) done <- true }() } // wait for all goroutines to complete before exiting for _ = range values { <-done } } 這個範例是在學GO蠻經典的例子,結論是永遠不要在gorutine裡面直接使用外面的變數。 因為goruntine宣告後並不是馬上建立的,可能等一下才建立,以及複數個gorutine建立起來可能沒有順序性,此時外面的變數已經不知道跑到哪裡去了。 有兩個比較直觀的解法,一個是每次都直接將變數傳入goruntine的function

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART3

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART3這裡有 Values   Writing Code   Pointers and Allocation   Concurrency --Values-- Why does Go not provide implicit numeric conversions? 要考量的問題很多,轉換後是否為正數?值會多大?會不會溢位?是否可用? 自動轉換數字型態所帶來的混亂大過好處,沒有特別設計的compile架構很難滿足這個機制。 對GO而言即使64-bit的系統,int也不等於int64的型態。 Why are maps built in? 如strings一樣重要,這種結構可以滿足廣大的定義需求。 map結構,雖然語意寫法稍微不方便了點,但complie的速度快,這應該是可被接受的合理平衡點。 Why don’t maps allow slices as keys? map 裡面的查找,需要equality 運算子(我不清楚這個equality是什麼)。 對於slice是沒有equality 運算子的,但array,和struct有,所以可以當作map的keys。(我的天呀) (會問這種問題,真是超乎想像) Why are maps, slices, and channels references while arrays are values? 為什麼map, slices, and channels 是參考,arrays 是數值。 我的理解是在講call by references 的 references,還有 call by value的value。 map, slices, and channels 是指標,所以不可能生出非指標型態的實體,GO也掙扎的想把array做成這樣。 但會有一些很複雜的作用,所以GO放棄,還是維持value的可用性較高。(這部分看得不是很懂)  -- Writing Code--   How are libraries documented? godoc 提供的功能豐富,可以滿足

[Go] Golang了解 array 和 slice 的差異,簡單說明

array 一開始就宣告大小,不可以再變動。 slice 則是動態增長。 對於array的型態來說,[2]int 和 [3]int 會是不同的型態,長度大小可以理解為某種附加型態,要有指定大小+中括號才是array。 array和slice在執行速度上也差異很多,在我macbook pro 2017,的簡單測試1到100階乘的加總,一個是nanoseconde的運算時間,一個是microsecond。 Created Date : 2018/08/07 Last Updated Date : 2018/08/07

[Go] Golang用法 function input & output 參數可以同樣型態放一起

參數太長該怎麼辦,同樣類型的可以寫在一起。 這件事情我知道的時候還蠻訝異的,同時,又得知不只傳入的參數可以這樣,return的型態也可以這樣搞。 另外,若事先指定回傳的變數名稱,可以在function當中各處先assign你要的回傳值到這些變數。 Input的參數可以類型寫一起 func GetMyData(name string, sex string, birthday string,id int, number int) { } // 可以改寫為 func GetMyData(name, sex, birthday string, id, number int) { } return的參數也可以類型寫一起,並且偷偷宣告變數名稱 func GetMyData(name, sex, birthday string, id, number int) (bool,bool){ } // 可以指定命名 func GetMyData(name, sex, birthday string, id, number int) (isOK bool, isPassed bool){ } // 當然也可以匯集 func GetMyData(name, sex, birthday string, id, number int) (isOK, isPassed bool){ } function 中串插要回傳的值 func GetMyData(name, sex, birthday string, id, number int) (bool, bool){ isOK := true isPassed := false return isOK, isPassed } // 就可以改寫為 func GetMyData(name, sex, birthday string, id, number int) (isOK, isPassed bool){ isOK = true // 中間有些co

[Go] Golang用法 package import 前面的底線

package import 前面的底線 init() 是GO 的關鍵字,每個package都存在一個這樣預設的init() 對於main package來說,在進入main()之前,會先執行init(),如果你有寫在這個package某處的話。 在import package時 對於引用package來講,只會執行這個package的init(),其他部分不會用到。 如使用gorm,我只想用mysql的部分,因此按照文件,我要import “github.com/go-sql-driver/mysql”,但前面加上_ 即可 import ( _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) Created Date : 2018/08/03 Last Updated Date : 2018/08/03

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART2

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART2這裡有   Types   Types Is Go an object-oriented language? Go 說是,也不是,有OO的風格,但沒有『繼承』,在GO裡面的interface也跟其他語言的interface有所不同。 透過interface可以達到某些類似subclass的目的,但GO聲明這樣的東西,絕對不等於subclass。 (BOX 和 UBOX 的概念我不清楚,找到的參考是 https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing ,但還是不懂意思,GO表示可以把ubox integer也塞進struct,這很厲害?) 再次聲明,沒有了『繼承』,少了負擔感覺真好。 (OS: 你到底多討厭繼承,這好像我第三次看到了,然後我也覺得就直說不是傳統物件導向的語言,別甲仙啦。) How do I get dynamic dispatch of methods? 『dynamic dispatch of methods』是一個概念,搭配Polymorphism的概念一起看,在GO能做到這件事的唯一方式就是透過interface。 在struct裡面的method和具體的method都是靜態處理。 Why is there no type inheritance? GO想走別的方向,不想要有『繼承』。 沒有『繼承』帶來實質上的好處,『繼承』機制所需要的紀錄彼此關係這件事情,造成很高的複雜度和負擔。 GO的interface可以達到你的目的,再者,沒有了『繼承』就不需要管型態與interface的『明確關係』,每個type可以乾淨的跟interface結合。 (所以其他OO語言,有繼承的type,如果有使用interface,他們之間會定義某種關係狀態,拖累某些處理和速度是嗎?) 舉例fmt.Fprintf 可以印出任何型態的東西,io.Writer可以各種寫入,就是靠『沒繼承』+ 『interface

[Go] 閱讀心得 不負責任翻譯 Golang Frequently Asked Questions (FAQ) PART1

https://golang.org/doc/faq 官方FAQ 提供一些有趣的資訊,很認真的試圖都理解一下,由於內容太多,拆成幾個部分來看。 PART1這裡有  Origins  Usage    Design --Origins-- What is the purpose of the project? 依賴管理對於現在語言非常重要,C語言有著絕佳的速度,但header file的方式在管理依賴這件事上實在非常糟糕。於是想要一個速度快,依賴管理方面又能滿足我們的語言。 沒有『繼承』的概念,這點可以省略『判斷兩個型態彼此之間的關係』所花的時間。(這點蠻有趣的,我不曉得『繼承』需要這樣的cost) Go準備完整的garbage-collected ,來足以應付併發與溝通問題。(以目前所學,各處聽到GO的gb機制多少令人詬病XD) Go是為了多核心機器所設計的語言。(沒錯,這點非常重要!) What is the status of the project? Go 是個開源的poject,有Google撐腰,version 1 是個長期支援的版本。 version 2 改天指日可待! What’s the origin of the mascot? (吉祥物,略) What is the history of the project? (歷史,略) Why are you creating a new language? 這裡說目前主要的程式語言,若達到簡單好上手(直譯式、弱型別)的,那麼就不能滿足安全又快速的條件(我想這是以事先編譯的角度來看)。 Go 想要達到簡單、安全又快速,可以處理併發、多核心的機器。 GO語言目標:在 單一一台機器上,可以快速與有效的執行龐大的程式 。 What are Go’s ancestors? Go 主要血統是C語言,但參雜很多語言的概念,還有新的。 What are the guiding principles in the design? (部份不太懂) 捨棄繼承,type就是純粹的type,而不用聲明type和type的關係(講繼承) 保持概念和原則的純粹,method -->實現任何類型; stru

[Go] 型態轉換 type convert

常用的型態轉換小筆記 int 轉 float64 float64(i) int64 轉 string i := int64(32) str := strconv.FormatInt(i, 10) 參數1 : 要轉的數字 參數2 : 指定進位制,10 >>> 10進位的意思,也可以帶入16 >>> 幫你轉成16進位,再變成字串 string 轉int64 s := "66" i, err := strconv.ParseInt(s, 10, 64) 參數1 : 要轉的字串 參數2 : 指定進位制 參數3 : 位元型態,64 >>> int64,32 >>> int32,8 >>> int8 string 轉 float64 i := "10.53" strconv.ParseFloat(i, 64) 參數1 : 要轉的字串 參數2 : 位元型態,64 >>> float64,32 >>> float32 float64 轉 string i := 23.957232 strconv.FormatFloat(i, ‘f’, 4, 64) 參數1 : 要轉的字串 參數2 : ‘b’ >>> 二進位表示 ’e’ >>> 指數表示(科學符號) ‘E’ >>> 同’e’ ‘f’ >>> 不使用科學符號 ’g’ >>> 大指數表示(我不知道這啥) ‘G’ >>> 同’g’ 參數3 : 小數點後幾位 參數4 : bit-size,原本是float32帶32,float64,帶64 [100]byte 轉string s := string(byteArray[:]) []byte 轉string s := string(byteArray) 有趣的點是byte array 是無法直接轉成string,必須先轉成slice再到string,所以若原本是byte

[Go] 閱讀心得 Why should you learn Go?

Why should you learn Go? 原文網址 這邊文章介紹為什麼要使用Go語言,閱讀後,個人摘錄一些部分並記錄自己的心得。 PART 1 作者首先討論摩爾定律這件事情,並且認為這個定律是失敗的,卡在物理上的限制。其實我認為這個定律還沒完全失敗,如果時間拉長用5年、10年來看的話,哪天突破一個想像的限制,硬體所能提供的運算速度又會飄上去了。 We cannot add more and more cache to the processor to increase performance as cache have physical limits: the bigger the cache, the slower it gets. 這段話有如大學時上課唸到的教科書所述,加大cache並非萬能,越肥的體積占在CPU裡面,帶來的副作用跟幫助效用成反比。 Adding more core to the processor has its cost too. 這也沒錯,無限加core有極限,不是頂天的解法。推論的結果是不能依賴硬體,要靠軟體的協助。 然後作者說非常upset,現代的軟體來講,有效運用硬體資源的程度遠遠不夠,換句話落後很多硬體方面的成長。 這句話我在學生時代就有聽過,但不能夠深刻體會,直到我稍微了解了gorutine是什麼鬼東西。GOD ! 真的是軟體不夠力,還可以靠軟體再進化一個程度。 碰巧下個段落作者馬上就提到gorutine了,gorutine就是golang拿來突破物理限制的銀彈。 PART 2 作者說到Java、Python 是90年代的背景而生的,那時候只有單執行緒,雖然後來都可以執行多個執行緒,但併發、執行緒鎖、競爭、死結,新的執行緒生出需要很久,需要產生1MB以上的heap,更困難的是執行緒之間的溝通,這些不得不面對的問題拖累我們熟悉的這些程式語言。 這部分的背景之前我比較不清楚,但就我所知的Java,可不能小看,Java在管理這些東西運行的非常穩定,他有一套獨特的處理機制。讓我想到有如Apple當初推出iphone5時RAM只有1GB的大小,但人家速度就是吊打16GB RAM的HTC,HTC 掰~ 但單論『併發』的問題,JAVA也許真的很難與擁有

[Go] 指標 pointer with golang

以前學C和C++對指標有很大誤解,老師對不起,但您說的內容,學生當時真的不太懂,事隔多年我努力用比較簡白的文字來描述,彌補當年慘烈成績的遺憾。 以下三個都在說同樣的一件事,但我不知道為什麼以前透過function傳接球,腦袋轉不過來。 PART I b := 10 var a *int = &b 指標只能存位址(address) ,你要嘛弄個指標的型態(如範例是*int)去存人家位置,要嘛用一般的變數去存一般的值 PART II b := 10 a:= &b a 其實被宣告為*int PART III func main() { b := 10 setFunc(&b) } func setFunc(a *int) { } var a *int = &b 將『指標(命名為a) 指向b』用法就這樣,沒有別的,沒事不會亂用或單獨用『&』『*』 『int』 跟 『*int』雖然長得87分像,但兩個完全不一樣, 『int』叫做整數,『*int』如上的用途的時候叫做指標,指的對像是整數。如果『*int』可以改叫做『pointerToInt』之類的關鍵字,我大一也不會被當掉了,大概吧。 改值是另一件事, *a = 10,這時候的『星號』已經暗指a在之前已經被宣告成指標的type,這點很重要,『星號』在這時候的用途英文叫做 derefference , 中文有人叫做『提取』,不管你是一層指標,還是像C語言有人有點毛病寫了三層指標,都可以想成一層一層將內容提取出來的概念,一但用了『提取』(*a = 10),不管在哪裡都會被改到。 *a 絕對不等於 var a *int 的意思 *a : a 已經被宣告成指標,提取a 的內容 var a *int : a 被宣告為指標型態,就跟被宣告為int或者string一樣稀鬆平常,你對於int的變數只能放int,對於string的變數只能放string,那指標只能放位址,只是有點複雜,指標的型態一定還有個附加屬性,這裡是int,所以宣告為* int Created Date : 2018

[Go] 錯誤訊息歷經收集

panic: assignment to entry in nil map 原因:  map的使用一定要初始化,所以配合make一起用,雖然編譯的時候可以過關 正確寫法: reMapUser := make(map[string]ST.SingleUserObject) short write 原因:  實際寫入的內容比預期的短少,換句話說東西只寫入一部分,部分有丟失,自己是在用gorutine短時間寫入redis同一個key遇到 protoc-gen-go: program not found or is not executable –go_out: protoc-gen-go: Plugin failed with status code 1. 這是有使用套件protoco: https://developers.google.com/protocol-buffers/ 原因:  中途我改了GOPATH,把GOPATH 改回來就沒事 Created Date : 2018/07/30 Last Updated Date : 2018/07/31