本文目錄一覽:
- 1、GO語言學習系列八——GO函數(func)的聲明與使用
- 2、Golang入門到項目實戰 | golang 函數
- 3、Golang 中函數和方法的區別
- 4、golang 怎麼定義可變參數的函數
- 5、golang-redis系列——返回值助手函數(二)
GO語言學習系列八——GO函數(func)的聲明與使用
GO是編譯性語言,所以函數的順序是無關緊要的,為了方便閱讀,建議入口函數 main 寫在最前面,其餘函數按照功能需要進行排列
GO的函數 不支持嵌套,重載和默認參數
GO的函數 支持 無需聲明變量,可變長度,多返回值,匿名,閉包等
GO的函數用 func 來聲明,且左大括號 { 不能另起一行
一個簡單的示例:
輸出為:
參數:可以傳0個或多個值來供自己用
返回:通過用 return 來進行返回
輸出為:
上面就是一個典型的多參數傳遞與多返回值
對例子的說明:
按值傳遞:是對某個變量進行複製,不能更改原變量的值
引用傳遞:相當於按指針傳遞,可以同時改變原來的值,並且消耗的內存會更少,只有4或8個位元組的消耗
在上例中,返回值 (d int, e int, f int) { 是進行了命名,如果不想命名可以寫成 (int,int,int){ ,返回的結果都是一樣的,但要注意:
當返回了多個值,我們某些變量不想要,或實際用不到,我們可以使用 _ 來補位,例如上例的返回我們可以寫成 d,_,f := test(a,b,c) ,我們不想要中間的返回值,可以以這種形式來捨棄掉
在參數後面以 變量 … type 這種形式的,我們就要以判斷出這是一個可變長度的參數
輸出為:
在上例中, strs …string 中, strs 的實際值是b,c,d,e,這就是一個最簡單的傳遞可變長度的參數的例子,更多一些演變的形式,都非常類似
在GO中 defer 關鍵字非常重要,相當於面相對像中的析構函數,也就是在某個函數執行完成後,GO會自動這個;
如果在多層循環中函數里,都定義了 defer ,那麼它的執行順序是先進後出;
當某個函數出現嚴重錯誤時, defer 也會被調用
輸出為
這是一個最簡單的測試了,當然還有更複雜的調用,比如調試程序時,判斷是哪個函數出了問題,完全可以根據 defer 打印出來的內容來進行判斷,非常快速,這種留給你們去實現
一個函數在函數體內自己調用自己我們稱之為遞歸函數,在做遞歸調用時,經常會將內存給佔滿,這是非常要注意的,常用的比如,快速排序就是用的遞歸調用
本篇重點介紹了GO函數(func)的聲明與使用,下一篇將介紹GO的結構 struct
Golang入門到項目實戰 | golang 函數
函數的go語言中的一級公民,我們把所有的功能單元都定義在函數中,可以重複使用。函數包含函數的名稱、參數列表和返回值類型,這些構成了函數的簽名(signature)。
函數在使用之前必須先定義,可以調用函數來完成某個任務。函數可以重複調用,從而達到代碼重用。
go語言函數定義語法
語法解析:
go語言函數定義實例
定義一個求和函數
定義一個比較兩個數大小的函數
go語言函數調用
當我們要完成某個任務時,可以調用函數來完成。調用函數要傳遞參數,如何有返回值可以獲得返回值。
運行結果
Golang 中函數和方法的區別
在接觸到go之前,我認為函數和方法只是同一個東西的兩個名字而已(在我熟悉的c/c++,python,java中沒有明顯的區別),但是在golang中者完全是兩個不同的東西。官方的解釋是,方法是包含了接收者的函數。到底什麼意思呢。
首先函數的格式是固定的,func+函數名+ 參數 + 返回值(可選) + 函數體。例
func main()
{
fmt.Println(“Hello go”)
}
在golang中有兩個特殊的函數,main函數和init函數,main函數不用介紹在所有語言中都一樣,它作為一個程序的入口,只能有一個。init函數在每個package是可選的,可有可無,甚至可以有多個(但是強烈建議一個package中一個init函數),init函數在你導入該package時程序會自動調用init函數,所以init函數不用我們手動調用,l另外它只會被調用一次,因為當一個package被多次引用時,它只會被導入一次。
package main
import (
“demo/mypackage”
“fmt”
)
func main() {
fmt.Println(“Hello go…. I = “, mypackage.I)
}
運行結果:
我們可以看到,程序為我們自動調用了兩個init函數,並且是按照順序調用的。
下面來看方法。
package main
import “fmt”
type myint int
//乘2
func (p *myint) mydouble() int {
*p = *p * 2
return 0
}
//平方
func (p myint) mysquare() int {
p = p * p
fmt.Println(“mysquare p = “, p)
return 0
}
func main() {
var i myint = 2
i.mydouble()
fmt.Println(“i = “, i)
i.mysquare()
fmt.Println(“i = “, i)
}
運行結果:
我們可以看到方法和函數的區別,方法在func關鍵字後是接收者而不是函數名,接收者可以是自己定義的一個類型,這個類型可以是struct,interface,甚至我們可以重定義基本數據類型。我們可以給他一些我們想要的方法來滿足我們的實際工程中的需求,就像上面一樣我重定義了int並給了它一個乘2和平法的方法,這裡我們要注意一個細節,接收者是指針和非指針的區別,我們可以看到當接收者為指針式,我們可以通過方法改變該接收者的屬性,但是非指針類型缺做不到。
這裡的接收者和c++中的this指針有一些相似,我們可以把接受者當作一個class,而這些方法就是類的成員函數,當接收者為指針類型是就是c++中的非const成員函數,為非指針時就是const成員函數,不能通過此方法改變累的成員變量。
golang 怎麼定義可變參數的函數
golang定義可變參數的函數方法是:
—- 採用ANSI標準形式時,參數個數可變的函數的原型聲明是:
type funcname(type para1, type para2, …)
—- 這種形式至少需要一個普通的形式參數,後面的省略號不表示省略,而是函數原型的一部分。type是函數返回值和形式參數的類型。
—- 採用與UNIX System V兼容的聲明方式時,參數個數可變的函數原型是:
type funcname(va_alist)
va_dcl
—- 這種形式不需要提供任何普通的形式參數。
type是函數返回值的類型。va_dcl是對函數原型聲明中參數va_alist的詳細聲明,實際是一個宏定義,對不同的硬件平台採用不同的類型來定義,但在最後都包括了一個分號。因此va_dcl後不再需要加上分號了。va_dcl在代碼中必須原樣給出。va_alist在VC中可以原樣給出,也可以略去。
此外,採用頭文件stdarg.h編寫的程序是符合ANSI標準的,可以在各種操作系統和硬件上運行;而採用頭文件varargs.h的方式僅僅是為了與以前的程序兼容。所以建議使用前者。
golang-redis系列——返回值助手函數(二)
從上一節的內容可知,Do() 和 Receive() 等方法的返回值,除了 error 外,是一個 interface{} 類型的返回值,因此當我們的複雜操作返回的不是基本數據類型時,就需要我們自己解析返回值,例如,當我們利用 HMGET 方法獲取一批返回值時,就需要對返回結果進行解析,具體如下:
由於返回值是多條數據,因此需要先將 reply 轉成 []interface 類型,然後在遍歷結果時在分別轉成 []uint8 (byte數組), 最後再轉成 string 類型。
隨着我們操作複雜度,數據解析的工作量也會非常大,(lua 腳本的使用,會使結果的解析更為複雜,因為可能存在多種類型的結果一起返回的情況,lua 腳本相關的內容會在下一節介紹)。
redigo 包中的返回值助手函數的存在,就是為了幫助我們完成這些枯燥繁瑣的數據解析過程。
返回值助手函數相關源碼路徑為 github.com/gomodule/redigo/redis/reply.go 提供的主要方法如下:
上述返回值助手函數的具體使用,應該依據具體的命令進行選擇。如果大家還記得上一節介紹的 Redis 基本數據類型,可能會有些疑問,對於 redis 來說,其數據據存儲本質都是 []bytes, 為什麼可以解析出 Int、int64、float等類型的數據呢?
我們以 Float64() 為例進行說明,具體源碼如下:
其實,返回值助手函數是將 []byte 類型的原始數據,利用 strconv.ParseFloat(string(reply), 64) 轉換成了 float64類型,因此在我們使用過程中返回值助手函數的選擇,應該基於業務和實際存儲的數據格式為依據。我們以第一小節的示例為例,看返回值助手函數如何降低我們的工作量,具體如下:
除了使用返回值助手函數對上述固定結構的結果進行解析外,redigo 包還提供了一個 Scan()函數用於解析自定義的複雜數據結構,我們依然以上一個示例進行說明,具體示例如下:
如果返回結果為結構化切片,也可以使用 canSlice() 方法,從而簡化 loop 處理的部分,具體示例如下:
通過上述的示例,我們介紹了 scan 函數的基本用法,但是細心的同學可能會發現嗎,為什麼數據寫入時,value 的類型為 []int64 但是讀取時只能按照 string 類型讀取呢。這是因為 Redis 底層存儲的數據本質都是 string 類型,。 無論是 HMSET 還是 MSET 最終都只能按照 string 類型讀取,因為其本質都是 hash 結構,不同之處僅在於 HMSET 是嵌套的 hash類型。 因此,[]int64 數據在寫入階段,就已經被自動處理為 []byte,寫入 redis 之後,len 和 類型 屬性會丟失。
如果強行按照 []int64解析將出錯:
如果 value 必須以結構化的數據存儲,那麼可以提前對要寫入的數據進行編碼,例如 json、protobuf 等,取出後再進行解碼獲得原始數據。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/187869.html