<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    少年阿賓

    那些青春的歲月

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

    不可或缺的函數(shù),在Go中定義函數(shù)的方式如下:

    func (p myType ) funcName ( a, b int , c string ) ( r , s int ) {     return } 

    通過函數(shù)定義,我們可以看到Go中函數(shù)和其他語言中的共性和特性

    共性

    • 關(guān)鍵字——func
    • 方法名——funcName
    • 入?yún)?#8212;—— a,b int,b string
    • 返回值—— r,s int
    • 函數(shù)體—— {}

    特性

    Go中函數(shù)的特性是非常酷的,給我們帶來不一樣的編程體驗(yàn)。

    為特定類型定義函數(shù),即為類型對(duì)象定義方法

    在Go中通過給函數(shù)標(biāo)明所屬類型,來給該類型定義方法,上面的 p myType 即表示給myType聲明了一個(gè)方法, p myType 不是必須的。如果沒有,則純粹是一個(gè)函數(shù),通過包名稱訪問。packageName.funcationName

    如:

    //定義新的類型double,主要目的是給float64類型擴(kuò)充方法 type double float64  //判斷a是否等于b func (a double) IsEqual(b double) bool {     var r = a - b     if r == 0.0 {         return true     } else if r < 0.0 {         return r > -0.0001     }     return r < 0.0001 }  //判斷a是否等于b func IsEqual(a, b float64) bool {     var r = a - b     if r == 0.0 {         return true     } else if r < 0.0 {         return r > -0.0001     }     return r < 0.0001 }  func main() {     var a double = 1.999999     var b double = 1.9999998     fmt.Println(a.IsEqual(b))     fmt.Println(a.IsEqual(3))     fmt.Println( IsEqual( (float64)(a), (float64)(b) ) )  } 

    上述示例為 float64 基本類型擴(kuò)充了方法IsEqual,該方法主要是解決精度問題。 其方法調(diào)用方式為: a.IsEqual(double) ,如果不擴(kuò)充方法,我們只能使用函數(shù)IsEqual(a, b float64)

    入?yún)⒅校绻B續(xù)的參數(shù)類型一致,則可以省略連續(xù)多個(gè)參數(shù)的類型,只保留最后一個(gè)類型聲明。

    如 func IsEqual(a, b float64) bool 這個(gè)方法就只保留了一個(gè)類型聲明,此時(shí)入?yún)和b均是float64數(shù)據(jù)類型。 這樣也是可以的: func IsEqual(a, b float64, accuracy int) bool

    變參:入?yún)⒅С肿儏?即可接受不確定數(shù)量的同一類型的參數(shù)

    如 func Sum(args ...int) 參數(shù)args是的slice,其元素類型為int 。經(jīng)常使用的fmt.Printf就是一個(gè)接受任意個(gè)數(shù)參數(shù)的函數(shù) fmt.Printf(format string, args ...interface{})

    支持多返回值

    前面我們定義函數(shù)時(shí)返回值有兩個(gè)r,s 。這是非常有用的,我在寫C#代碼時(shí),常常為了從已有函數(shù)中獲得更多的信息,需要修改函數(shù)簽名,使用out ,ref 等方式去獲得更多返回結(jié)果。而現(xiàn)在使用Go時(shí)則很簡(jiǎn)單,直接在返回值后面添加返回參數(shù)即可。

    如,在C#中一個(gè)字符串轉(zhuǎn)換為int類型時(shí)邏輯代碼

    int v=0;  if ( int.TryPase("123456",out v) ) {     //code } 

    而在Go中,則可以這樣實(shí)現(xiàn),邏輯精簡(jiǎn)而明確

    if v,isOk :=int.TryPase("123456") ; isOk {     //code } 

    同時(shí)在Go中很多函數(shù)充分利用了多返回值

    • func (file *File) Write(b []byte) (n int, err error)
    • func Sincos(x float64) (sin, cos float64)

    那么如果我只需要某一個(gè)返回值,而不關(guān)心其他返回值的話,我該如何辦呢? 這時(shí)可以簡(jiǎn)單的使用符號(hào)下劃線”_“ 來忽略不關(guān)心的返回值。如:

    _, cos = math.Sincos(3.1415) //只需要cos計(jì)算的值 

    命名返回值

    前面我們說了函數(shù)可以有多個(gè)返回值,這里我還要說的是,在函數(shù)定義時(shí)可以給所有的返回值分別命名,這樣就能在函數(shù)中任意位置給不同返回值復(fù)制,而不需要在return語句中才指定返回值。同時(shí)也能增強(qiáng)可讀性,也提高godoc所生成文檔的可讀性

    如果不支持命名返回值,我可能會(huì)是這樣做的

    func ReadFull(r Reader, buf []byte) (int, error) {     var n int     var err error      for len(buf) > 0  {         var nr int         nr, err = r.Read(buf)          n += nr         if err !=nil {             return n,err         }         buf = buf[nr:]     }     return n,err } 

    但支持給返回值命名后,實(shí)際上就是省略了變量的聲明,return時(shí)無需寫成return n,err 而是將直接將值返回

    func ReadFull(r Reader, buf []byte) (n int, err error) {     for len(buf) > 0 && err == nil {         var nr int         nr, err = r.Read(buf)         n += nr         buf = buf[nr:]     }     return } 

    函數(shù)也是“值”

    和Go中其他東西一樣,函數(shù)也是值,這樣就可以聲明一個(gè)函數(shù)類型的變量,將函數(shù)作為參數(shù)傳遞。

    聲明函數(shù)為值的變量(匿名函數(shù):可賦值個(gè)變量,也可直接執(zhí)行)

    //賦值 fc := func(msg string) {     fmt.Println("you say :", msg) } fmt.Printf("%T \n", fc) fc("hello,my love") //直接執(zhí)行 func(msg string) {     fmt.Println("say :", msg) }("I love to code") 

    輸出結(jié)果如下,這里表明fc 的類型為:func(string)

    func(string)  you say : hello,my love say : I love to code 

    將函數(shù)作為入?yún)ⅲɑ卣{(diào)函數(shù)),能帶來便利。如日志處理,為了統(tǒng)一處理,將信息均通過指定函數(shù)去記錄日志,且是否記錄日志還有開關(guān)

    func Log(title string, getMsg func() string) {     //如果開啟日志記錄,則記錄日志     if true {         fmt.Println(title, ":", getMsg())     } } //---------調(diào)用-------------- count := 0 msg := func() string {     count++     return "您沒有即使提醒我,已觸犯法律" } Log("error", msg) Log("warring", msg) Log("info", msg) fmt.Println(count) 

    這里輸出結(jié)果如下,count 也發(fā)生了變化

    error : 您沒有即使提醒我,已觸犯法律 warring : 您沒有即使提醒我,已觸犯法律 info : 您沒有即使提醒我,已觸犯法律 3 

    函數(shù)也是“類型”

    你有沒有注意到上面示例中的 fc := func(msg string)... ,既然匿名函數(shù)可以賦值給一個(gè)變量,同時(shí)我們經(jīng)常這樣給int賦值 value := 2 ,是否我們可以聲明func(string) 類型 呢,當(dāng)然是可以的。

    //一個(gè)記錄日志的類型:func(string) type saveLog func(msg string)  //將字符串轉(zhuǎn)換為int64,如果轉(zhuǎn)換失敗調(diào)用saveLog func stringToInt(s string, log saveLog) int64 {      if value, err := strconv.ParseInt(s, 0, 0); err != nil {         log(err.Error())         return 0     } else {         return value     } }  //記錄日志消息的具體實(shí)現(xiàn) func myLog(msg string) {     fmt.Println("Find Error:", msg) }  func main() {     stringToInt("123", myLog) //轉(zhuǎn)換時(shí)將調(diào)用mylog記錄日志     stringToInt("s", myLog) } 

    這里我們定義了一個(gè)類型,專門用作記錄日志的標(biāo)準(zhǔn)接口。在stringToInt函數(shù)中如果轉(zhuǎn)換失敗則調(diào)用我自己定義的接口函數(shù)進(jìn)行日志處理,至于最終執(zhí)行的哪個(gè)函數(shù),則無需關(guān)心。

    defer 延遲函數(shù)

    defer 又是一個(gè)創(chuàng)新,它的作用是:延遲執(zhí)行,在聲明時(shí)不會(huì)立即執(zhí)行,而是在函數(shù)return后時(shí)按照后進(jìn)先出的原則依次執(zhí)行每一個(gè)defer。這樣帶來的好處是,能確保我們定義的函數(shù)能百分之百能夠被執(zhí)行到,這樣就能做很多我們想做的事,如釋放資源,清理數(shù)據(jù),記錄日志等

    這里我們重點(diǎn)來說明下defer的執(zhí)行順序

    func deferFunc() int {     index := 0      fc := func() {          fmt.Println(index, "匿名函數(shù)1")         index++          defer func() {             fmt.Println(index, "匿名函數(shù)1-1")             index++         }()     }      defer func() {         fmt.Println(index, "匿名函數(shù)2")         index++     }()      defer fc()      return func() int {         fmt.Println(index, "匿名函數(shù)3")         index++         return index     }() }  func main() {     deferFunc() } 

    這里輸出結(jié)果如下,

    0 匿名函數(shù)3 1 匿名函數(shù)1 2 匿名函數(shù)1-1 3 匿名函數(shù)2 

    有如下結(jié)論:

    • defer 是在執(zhí)行完return 后執(zhí)行
    • defer 后進(jìn)先執(zhí)行

    另外,我們常使用defer去關(guān)閉IO,在正常打開文件后,就立刻聲明一個(gè)defer,這樣就不會(huì)忘記關(guān)閉文件,也能保證在出現(xiàn)異常等不可預(yù)料的情況下也能關(guān)閉文件。而不像其他語言:try-catch 或者 using() 方式進(jìn)行處理。

    file , err :=os.Open(file) if err != nil {     return err } defer file.Close()  //dosomething with file 

    后續(xù),我將討論: 作用域、傳值和傳指針 以及 保留函數(shù)init(),main()

    本筆記中所寫代碼存儲(chǔ)位置:

    posted on 2017-08-02 16:39 abin 閱讀(568) 評(píng)論(0)  編輯  收藏 所屬分類: golang

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: www国产亚洲精品久久久日本| 精品久久久久国产免费| 亚洲精品国产精品乱码不卡| 亚洲色偷精品一区二区三区| 四虎永久在线观看免费网站网址| 91亚洲国产在人线播放午夜| 无码精品国产一区二区三区免费 | 亚洲在成人网在线看| 在线日本高清免费不卡| 亚洲嫩模在线观看| 亚洲免费网站在线观看| 亚洲中文无码av永久| 野花高清在线观看免费3中文 | 国产AV无码专区亚洲AV麻豆丫| 免费国产小视频在线观看| 看一级毛片免费观看视频| 亚洲高清偷拍一区二区三区| 美女网站在线观看视频免费的| 亚洲欧洲成人精品香蕉网| 91精品免费观看| 亚洲av日韩专区在线观看| www.亚洲精品| 精品国产麻豆免费人成网站| 亚洲高清在线mv| 日韩免费一区二区三区| eeuss草民免费| 亚洲综合日韩中文字幕v在线| 黄网站色在线视频免费观看| 亚洲人片在线观看天堂无码| 亚洲成年人啊啊aa在线观看| 中国极品美軳免费观看| 亚洲熟妇无码爱v在线观看| 日本免费网站在线观看| 三级网站在线免费观看| 亚洲国产高清视频在线观看| 日本二区免费一片黄2019| 免费无码又爽又刺激一高潮| 亚洲剧情在线观看| 亚洲人成影院在线无码观看| 2021国内精品久久久久精免费| 亚洲第一成年免费网站|