go語言入門之-函數和方法

函數

函數聲明

函數生成包含函數的名字,形參列表,返回值列表(可選)以及函數體構成.數組

func name(parameter-list) (result-list) {
  body
}
複製代碼

須要注意一下幾點:函數

  1. 函數的形參列表和返回值列表組成函數的簽名,函數的簽名會在函數被調用的時候作校驗是否調用合法.spa

  2. 參數的傳遞是按值傳遞的.指針

  3. 支持多返回值.code

  4. 函數變量是有類型的,不符合函數簽名類型的調用會報錯對象

    func changeArr(a [3]int) {
       a[0] = 100
     }
     func getArr(a [3]int) (int, int) {
         return a[0], a[1] // 多返回值
     }
     func main() {
       test := [3]int{1,2,3}
       changeArr(test)
       fmt.Println(test[0]) // 1 數組是基本類型 值傳遞不會改變原數組
       a, b := getArr(test); // 1, 2
     }
     // 當形參的基本類型的時候,不會修改外部的值.當形參是引用類型的時候,有可能會修改外部的值.
    複製代碼

變長函數聲明

經過在參數列表最後的類型名稱以前使用省略號來聲明一個變長函數聲明.資源

func log(vals ...int) {
  for _, value := range vals {
    fmt.Println(value)
  }
}
func main() {
  b := []int{1,2,3}
  log(b...) // 1, 2, 3
  log(1,2,3) // 1, 2, 3
}
複製代碼

函數變量(匿名函數)

經過在func關鍵字後不指定函數的名字能夠聲明函數變量,這種方式函數能獲取整個詞法環境(外部的變量).開發

func add() func() int {
  var x int;
  return func() int {
    x++
    return x
  }
}
func main() {
  f := add()
  fmt.Println(f()) // 1
  fmt.Println(f()) // 2
}
複製代碼

錯誤處理機制

go語言經過普通的值來報告錯誤.常規的錯誤是開發者能夠預見而且決定錯誤的行爲的.這樣獲得的錯誤信息因爲沒有相應的堆棧信息而更加清晰.get

錯誤傳遞

調用者在調用函數發生錯誤的時候,在錯誤信息上添加更多的調用信息傳遞給上層.string

func test2()([]int, error) {
  return nil, errors.New("test2")
}
func test1() ([]int, error) {
  ret, err := test2()
  if err != nil {
    return nil, fmt.Errorf("test1 call test2 %v", err)
  }
  return ret, nil;
}
func main() {
  _, err := test1()
  fmt.Println(err); // test1 call test2 test2
}
複製代碼

defer

defer語句是普通的函數調用,defer語句能確保函數的return語句或函數執行完畢以後執行對應的defer函數.

func log() func() {
  fmt.Println("start")
  return func() { fmt.Println("end") }
}
func main() {
  defer log()()
  fmt.Println("test defer")
}
// 輸出 start test defer end
複製代碼
注意點
  1. defer執行匿名函數會獲取當前的詞法環境,有可能修改函數執行的結果.

  2. defer語句能保證函數執行完執行,某些狀況會致使資源沒法釋放.

    func readFills (filenams []string) {
       for _, filename := range filenams {
         f, err := os.Open(filename)
         defer f.Close()
       }
     }
     // 上面的例子會致使文件描述符被消耗沒法釋放,能夠在進行單獨的封裝來控制defer對資源的釋放.  
    複製代碼

方法

方法聲明

方法是聲明特定類型(對象)上能夠執行的函數. 一般能夠使用以下的方式聲明:

func (p structName) funcName(parameter-list) (result-list) {
  body
}  
// p 特定的類型(接受者)  聲明能夠在p類型上調用funcName的方法 
複製代碼

注意:

  1. 因爲方法的調用是p.funcName和獲取p結構體上的屬性一致,要注意同一類型上的命名衝突.

指針接收者方法

因爲方法會複製實參,當須要方法的調用對外界產生影響的時候,就須要經過指針類型來完成方法的聲明,以下面的例子:

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10} // 獲取指針
  p.ScaleBy(2) // p{20, 20}
  q := Point{1,2}
  q.ScaleBy(3)  // q{3,6} 當類型符合的時候,會進行隱式轉換 至關於 (&q).ScaleBy(3)
}  
複製代碼

方法變量和方法表達式

方法變量

能夠將一個特定類型的方法賦值給一個變量,這個變量稱爲方法變量.該方法變量已綁定到特定的接收者上(caller),經過傳遞形參就能夠完成方法的調用.一般用於綁定特定的接受者.

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10}
  scaleBy := p.ScaleBy
  scaleBy(2) // p{20, 20}
}  
複製代碼

方法表達式

type Point struct {
  x, y int
}

func (p *Point) ScaleBy(factor int) {
  p.x *= factor
  p.y *= factor
}

func main() {
  p := &Point{10, 10}
  scaleBy := (*Point).ScaleBy // 方法表達式
  scaleBy(p,2)
}複製代碼
相關文章
相關標籤/搜索