1. 程式人生 > >Go基礎之流程[if, for,switch]和函數[func]

Go基礎之流程[if, for,switch]和函數[func]

分享 ima 關鍵字 世紀 == 重復 pan dex 不同

流程控制
  流程控制有三大類:條件判斷, 循環控制, 無條件跳轉

  if:所有語言 都有的一種判斷:如果滿足就做 不滿足就做另一件

  if x > 5 {
  fmt.println("比5大")
  } else {
  fmt.println("比5小")
  }

  技術分享圖片

  不同點:GO在條件判斷語句裏允許聲明一個變量,作用範圍在該條件邏輯塊內

  if a := computedValue(); a>5 {
    fmt.println("比5大")
  } else {
    fmt.println("比5小")
  }

  a出了if語句塊那麽也就超範圍 失效了
  fmt.println(a)

  技術分享圖片

  多條件: if xxx{} else if xxx{} else{}

    技術分享圖片

  goto goto跳轉必須在當前函數內定義好的標簽。(標簽大小寫敏感)

  func myFunc() {
    i := 0
    Here:
    println(i)
    i++
    goto Here
  }

  技術分享圖片


for:
  Go裏控制邏輯,它可以用來循環讀取數據 又能控制邏輯 還能叠代操作
  for xx1, xx2, xx3 { xxx } 其中xx1,xx2, xx3都是表達式

  //例子
  package main
  import "fmt"

  func main(){
  sum :=0;
  for index :=0; index < 10; index ++ {
    sum += index
    }
    fmt.Println("sum is" , sum)
  }

技術分享圖片

  有時候需要進行多個賦值操作,go沒有 所以使用平行賦值i, j= i + 1 ,j-1

  有時候可以忽略條件1和條件3
  sum := 1
  for ; sum <1000; {
    sum += sum
  }

  技術分享圖片


  ; 也可以省略

  在循環體中有兩個關鍵操作 break和continue。break跳出循環 continue 跳出本次循環

  break 和 continue 可以跟著標號 用來調到多重循環中的外層循環

  for配合 range 可以用於讀取slice和maip的數據

  for k, v:=range map {
    fmt.println("map",k)
    fmt.println("map",v)
  }

  !!!由於GO支持"多值返回",並且對"多聲明變量不用會報錯"在這種情況下 可以使用_來丟棄不需要使用的返回值

  for _, v := range map{
    fmt.Println("maps val:",v)
  }

switch
  有時候你需要寫很多的if-else來實現邏輯處理那麽可以用switch來代替

    switch sexpr {
    case expr1:
      some instructions
    case expr2:
      some instructions
    case expr3:
      some instructions
    default:
      other code
    }

  其中 sexpr 和exprx 的類型要保持一致。Go的switch非常靈活,表達式不必是常量或證書,執行過程從上到下,直到找到匹配項:
  如果switch沒有表達式,它會匹配true

  go裏面switch中 默認每個case後面帶有break,配對成功後不會向下執行而是跳出switch 但是可以用fallthrough 強制執行後面的case代碼

函數:
  函數是Go裏面的核心設計,通過關鍵字func來聲明

  func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {

  //這裏處理邏輯代碼
  //返回多個值
    return value1, value2
  }

  func 是聲明一個函數 funcName
  函數可以有一個或者多個參數,每個參數後面帶有類型,通過,分割
  函數可以返回多個值


  //例子
  func max(a,b int) int {//a,b int 都是int 縮略一個int
    if a > b {
      return a
    }
    return b

  }

  func main() {
    x := 3
    y := 4
    z := 5

    max_xy := max(x, y) //調用函數max
    max_xz := max(x, z)
    fmt.Printf("max(%d,%d)=%d\n", x, y, max_xy)
  }


  多返回值

    Go函數支持變參,接受變參的函數是有著不定數量的參數的 但是類型保持一致
  func myfunc(arg ...int) {}
    arg ... int 告訴GO這個函數接受不定數量的參數 在函數體中arg是個slice

  for _, n := range arg {
    fmt.Pringtf("and the number is : %d\n", n)
  }

傳值和傳指針

    當我們傳一個參數值到被調用函數裏面時,世紀穿了這個值得一份copy 當在被調用函數中修改參數值的時候,
  調用函數中相應實參不會發生任何變化,因為數值變化只作用在copy上。

  例子:
  package main
  import "fmt"

  // 函數實現+1操作
  func add1(a int) int {
    a = a + 1
    retrun a //返回一個新值
  }

  func main() {
    x := 3
    fmt.Println("x =", x) //應該輸出 "x = 3"
    x1 := add1(x) //調用add1()
    fmt.Println("x + 1 =", x1) //應該輸出"x+1 =4"
    fmt.Println("x = ", x) //應該輸出 "x = 3"
}

!!!上面x 調用了 add1(x) 並且在add1中執行 a = a + 1 操作,但是x變量的值沒有發生變化
解析原因: 當我們調用add1的時候 add1接收的參數其實是x的copy 而不是x本身

  如果傳本身呢? 那就是要傳指針了啊

    package main
    import "fmt"
    //簡單的一個函數,實現了參數+1的操作
    func add1(a *int) int {
    *a = *a + 1 //修改了a的值
    retrun *a //返回新值
    }

    func main() {
      x := 3
      fmt.Println("x=", x) //應該輸出"x=3"

      x1 := addr1(x)
      fmt.Println("x+1", x) //應該輸出 4
      fmt.Println("x", x) //應該輸出4

    }

  // 傳指針的好處
  1.傳指針使得多個函數能操作同一個對象
  2.傳指針比較輕量級(8bytes),只是傳內存地址,我們尅用指針傳遞體積大的結構體。
  如果用參數值傳需要copy會花額外多的系統開銷。所以傳遞大的結構體的時候,用指
  針是一個明確的選擇

  3.Go語言中string, slice, map這三種類型的實現機制類似於指針 可以直接傳遞 不用取地址後傳遞指針

defer:
GO語言中有種不錯的設計 延遲語句 defer。可以在函數中添加多個defer.並且defer按照逆序進行執行

  func ReadWrite() bool{
  file.Open("file")
  //做一些工作
  if filurex {
    file.Close()
    retrun false
  }
  if filurey {
    file.Close()
    retrun false
  }
  file.Close()
  retrun false
  }

上面代碼太重復 defer解決了這個問題

  func ReadWriter() bool{
  file.Open("file")
  defer file.Close()
  if failurex {
    return false
  }
  if failureY {
    renturn false
  }
  return ture
  }

!!!如果很多defer引用,那麽defer是采用後進先出的模式

函數作為值,類型

  在Go中函數也是變量之一 可以用type來定義。它的類型就是所擁有相同的參數,相同的返回值的一種類型

type typeName func() type

package main
import "fmt"

type testInt func(int) bool //聲明了一個函數類型

func isOdd(integer int) bool {
if integer % 2 == 0 {
return false
}
retrun true
}

func isEven(integer int) bool {
if integer % 2 == 0 {
return true
}
retrun false
}

// 聲明的函數類型在這個地方做了一個參數

func filter(slice []int, f testInt) []int {
var result [] int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}

func main() {
slice := [] int {1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) // isOdd這個函數當做值 傳遞到了 filter這個函數裏邊
fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven)
fmt.Println("Even elements of slice are: ", even)
}

  用途: 函數當做值 和類型在我們寫一些通用接口時候非常有用 上面例子中testInt類型是個函數類型。 我們可以實現很多種邏輯使得我們程序變得非常靈活

panic和Recover

main 函數 和Init 函數
  GO裏面有兩個保留函數: init函數 (應用於所有package) 和main函數 (只能應用於package main)
  這2個函數定義時候不能有任何參數和返回值
  兩個函數一個包只限制有一個
  GO會自動調用init() 和main() 不需要任何地方調用
  init() 是可選的 但是main 是必須的
  先執行main包 --- 然後導入其他包 重復只導入一次 ----init包

import 包
  GO代碼經常用到import這個命令來導入包文件
  import( "fmt")
  fmt是Go語言的標準庫 , 去goroot 下加載該模塊,
  go也支持其他2種方式來加載自己模塊
  1.相對路徑 :import "./model" //當前文件同一目錄的model目錄,不推薦這種方式導入
  2.絕對路徑 : import "shorturl/model" //架子啊gopath/src/shorturl/model模塊

  特殊導入import
  1.點操作:
  import(
  .  "fmt"
  )
  這個.的意思是 這個包導入 有點 後在引用這個包的函數時候不需要前綴 ---> print()
  2.別名操作
  import(
    f "fmt"
  )
  別名操作調用包函數時候 前綴變成我們的前綴 ---> f.print()

  3._操作
  import (
    "database/sql"
    _"github.com...."
  )
  _操作就是引入該包,不引入包裏面函數,而是調用該包裏面的init函數

2017年12月23日13:49:48 [小路寫·過去篇]

Go基礎之流程[if, for,switch]和函數[func]