Golang Pointer

前言 指標大概是我一開始學習golang最不適應的概念,最一開始學程式是由JavaScript入門,到wehelp後再學習用python 的flask框架寫網頁,這兩種語言都沒有指標的概念。而Go為了實現更高效的演算法及展現其高併發的特性,所以存有指標的方法來操作內存,當然相信自己學習時間不算久,也非EE 或CS背景,對指標瞭解可能還不夠全面,只能盡力就我了解的進行說明,如果有錯還請各方大神指正。 值 & 指標 當我們將int、string、struct這類的值傳給函式的時候(圖一),Go語言會在函式中複製這些值,建立新的變數,也就代表如果是在函式對參數做修改時候,原始的值是不會有影響的,而如果要修改原本的值,就要透過所謂的 指標變數。 (圖一,圖片來源 : Udemy Go: The Complete Developer’s Guide (Golang)) 我們可以在記憶體儲存資料非常簡單看成是一個抽屜,每個變數到會找到一個抽屜來儲存資料,而每個抽屜都有一個地址對應一筆資料(圖二),所謂的值與指標變數的關係可以參考圖三,也可以幫助理解。 宣告一個int型別的變數x,其值初始化為3,這個3在記憶體裡面會有個地址0x88FFF。並可以透過在變數前面加上ampersand符號,取得該變數在記憶體的地址。 宣告一個int型別的指標變數xPtr,*int代表一個指向int的指針,為一種type description。並透過將xPtr初始化為&x,取得該變數在記憶體的地址。 最後如果有需要存取原本的值,或修改原本的值,可以透過在指標變數前面加上*符號進行反解(dereferencing)。如果(ex : fmt.Println(*xPtr)可以得到3 )。 (圖二,自行繪製) (圖三,圖片來源 : Golang 指標基礎 Pointer - 記憶體位址、指標變數與資料型態、反解指標 By 彭彭) 介紹完值和指標宣告與反解的流程,會發現用到兩次*符號,但這兩次其實是代表不同個功用,參考下圖四 (圖四,自行繪製) 同時繪製圖五再次說明*符號與&符號的當作運算符號時候的功能 (圖五,自行繪製) 實作程式碼 以下面程式碼為例,一開始會先印出x等於3,但當我們將int傳給函式的時候,會在函式複製值,建立新的變數,所以如果要修改原本的值,傳入的變數必須為指標變數,故modifyInt函式的參數為(x *int)。 而當我們定義型別為*int,傳入的參數就必須是記憶體位置,故使用&x作為參數帶入modifyInt()函式,最後透過在modifyInt()使用*x進行反解,取得原本記憶體位置的值並重新賦值為50,可以發現不管是一開始的x變數,或是執行完modifyInt()函式的x變數,其值都變成50了。 package main import "fmt" var x int=3 func modifyInt(x *int) { *x = 50 fmt.Println("Inside function :", *x) } func main() { fmt.Println("At first, x eqaul to :", x) modifyInt(&x) fmt....

October 22, 2023 · 1 min

Golang Function

宣告函式 函數就像個果汁機,使用者丟什麼食材進去,果汁機可以根據不同的設定(運算邏輯),產出不同的結果。在Go裡面使用函數的方式其實和JavaScript、Python很像,不管是傳入的參數值或是返回值得類型都是可選擇的,最大的不同則是是如果有return的話一定要定義輸出的類型,其宣告格式如下 func functionName([parameter list])[return type]{ //運算邏輯 } 最簡單呼叫函式的方式就是沒有任何傳遞任何參數,與要求回傳的類型 func main() { newCard() } func newCard() { fmt.Println("Ace of Spades") } // Ace of Spades 如在main函式裡面,呼叫add(5,3),add函式無論如何都會回傳int類型的結果。 值得注意的是,因為Go是一個強型別(strongly typed)語言,在執行階段會檢查型別,因此如果我們函式定義返回int,在第三行如果是return字串就會出現錯誤。 func add(x int, y int) int { return x + y //return "8" } func main() { fmt.Println(add(5, 3)) } // 8 此外在函式裡面如果也可以返回多個值,如下面compute function 定義回傳兩個int類型的結果 func main() { fmt.Println(compute(5, 3)) } func compute(x int, y int) (int, int) { return x * y, x + y } // 15, 8 參數傳遞 在Go語言裡面,參數的傳遞都是都透過Pass by value,實際傳遞時會將參數複製一份到函式中, 因此在函式中對參數進行修改並不會影響原本的值。 如下為官網原文...

October 7, 2023 · 2 min

Golang String

Golang 字串 String in Go 在Go語言中透過雙引號 "" 傳達的文字訊息,其預設型態就是string。有以下特色 字串是唯讀的一但建立就無法改變,但可以使用 + 進行串接 為位元組並透過UTF-8進行編碼 使用雙引號 "" 不可換行,如要換行可以使用反引號 ` ,反引號會保留換行和空白字元 因為之前主要是學習JS和Python居多,關於第二點一開始在go做字串擷取時較為不習慣,下面先舉三個例子來說明在go裡面的字串其實就是位元組 : 一 : 透過%x進行16進位的輸出 fmt.Printf("%x","Golang 您好") // 476f6c616e6720e682a8e5a5bd 我們可以發現47是「G」這個位元組以16進位表示,6f則是小寫的o,20為空白。 然後在UTF-8裡面一個中文字為3 bytes,所以e682a8代表「您」這個字以16進位輸出之結果 二 : 利用[]取得字串的位元組資料 str := "Golang 您好" fmt.Println(str[0]) // 71 fmt.Println(str[0:3]) // Gol 因為string是以byte型式儲存,所以[0]會得到G的位元組資料,相較於第一個範例因為透過%x進行格式化輸出,也就是沒有轉為16進位,以10進位結果表示為71 有個蠻有趣的是,如果我透過索引只取一個數字,會得到該位置的byte並以Unicode表示,但如果索引有如上寫成[0,3],就會印出位置為0 1 2的字串 三 : 使用len方法 str := "Golang 您好" fmt.Println(len(str)) // 13 因為string是透過UTF-8進行編碼,而一個中文字代表 3bytes,所以str字串長度為13 bytes. 取得字串裡的文字 從上面的第二個例子,如果我們透過fmt.Println(str[0])只是取得,該字串的Unicode值,那我們可以如何取得? 第一個方法可以透過string方法 str := "Golang 您好" fmt.Println(string(str[0])) // G fmt.Println(string(str[8])) // ½ 這方法如果是抓取英文字母或是數字沒有問題,因為每個字元後面就是一個byte。但因為中文字對應UTF-8的編碼有三個bytes,會造成不能訪問這個中文字完整的字元,而會出現錯誤。 為了解決這個問題,建議如果要讀取字串中的字元,可以將該字串先轉成rune類型的slice,[]rune,這樣會將UTF-8編碼的位元組,轉換為Unicode的碼點,可以在特定索引取得特定字元,範例程式碼如下...

October 1, 2023 · 1 min