1. 程式人生 > 其它 >Go通關05:函式和方法的不同之處!

Go通關05:函式和方法的不同之處!

函式

函式宣告

func funcName(params) result {
  body
}
  • 關鍵字 func 用於宣告一個函式
  • funcName 函式名
  • params 函式的引數
  • result 是函式的返回值,可以返回多個返回值,如果沒有可以省略。
  • body 函式體

示例
1.

  • a、b形參型別一致,可以省略其中一個型別的宣告
func sum (a, b int) {
  return a + b
}

2.多值返回

  • 返回值的部分型別定義需要小括號括起來。
func sum (a, b int) (int,error) {
  if a <0 || b <0 {
    return 0, errors.New("a或b不能是負數")
  }
  return a + b, nil
}

3.命名引數返回

  • 函式中給命名返回引數賦值,相當於函式有了返回值,所以可以忽略 return 後要返回的值了。
func sum (a, b int) (sum int,err error) {
  if a <0 || b <0 {
    return 0, errors.New("a或b不能是負數")
  }
  sum = a + b
  err = nil
  return
}

4.可變引數

  • 函式的引數是可變的
  • 定義可變引數,只要在引數型別前加三個點 ... 即可
  • 可變引數的型別其實就是切片,下面示例中 params 的引數型別是 []int
func sum(params ...int) int {
    sum := 0
    for _, i := range params {
        sum += i
    }
    return sum
}

包級函式

  • 函式都會從屬於一個包,我們自定義的函式屬於 main 包。Println 函式屬於 fmt 包。
  • 想要呼叫其他包內的函式,那麼那個函式名稱首字母要大寫,使其作用域變為公有的。
  • 函式首字母小寫,只能在同一個包中被呼叫

匿名函式和閉包

匿名函式就是沒有名稱的函式。

func main(){
  //注意,sum 只是一個函式型別的變數,不是函式名字
  sum := func(a, b int) int {
    return a + b
  }
  fmt.Println(sum(1, 2))  // 3
}

匿名函式可以在函式中進行巢狀,這個匿名函式稱為內部函式,內部函式可以使用外部函式的變數,這種方式就是閉包。

func main (){
  sm := sum()
  fmt.Println(sum())
  fmt.Println(sum())
  fmt.Println(sum())
}

func sum () func() int{
  i := 0
  return func ()int{
    i++
    return i
  }
}

//結果為:
1
2
3

由於閉包函式,sum 函式返回一個匿名函式,匿名函式持有外部函式 sum 的變數 i,所以在main函式中,每次呼叫 sum(),i的值就會 +1。

在 Go 語言中,函式也是一種型別,可以作為函式型別的變數、引數、或者一個函式的返回值。

方法

方法和函式類似,不同之處就是方法必須有一個接收者,這個接收者是一個“類”(型別),這樣這個方法就算屬於這個“類”。

type Name string
func (n Name)String(){
  fmt.Println("name is ", n)
}
  • 示例中 String() 就是 Name 這個型別的方法
  • 接收者需要加在 func 和方法名之間,使用()
  • 接收者: (變數,型別)

使用:

func main(){
  name := Name("無塵")
  name.String()
}
//出處
name is 無塵

值型別接收者、指標型別接收者

方法的接收者可以使用值型別(例如上面示例)或者指標型別。
如果接收者是指標,那麼對指標的修改是有效的:

func (n *Name) Modify(){
  *n = Name("wucs")
}

func main(){
  name := Name("無塵")
  name.String()
  name.Modify()
  name.String()
}

//輸出
name is  無塵
name is  wucs

注意:在呼叫方法時,傳遞的接收者實質上都是副本,只不過一個是值副本,一個是指向這個值的指標的副本。指標指向原有值,所以修改指標指向的值,也就修改了原有值。
方法的呼叫者,可以是值,也可以是指標((&name).Modify()),Go 語言會自動轉義,我們無需關心。

方法表示式

方法可以賦值給變數

name := Name("無塵")
//方法賦值給變數,方法表示式
n = Name.String
//要傳一個接收者name進行呼叫
n(name)

無論方法是否有引數,通過方法表示式呼叫,第一個引數必須是接收者,然後才是方法自身的引數。