函數(shù) (function)
函數(shù)可以沒有參數(shù)或者接受多個參數(shù)。
當連續(xù)兩個或多個函數(shù)的已命名形參類型相同時,除最后一個類型以外,其它都可以省略。
func add(x, y int) int {
return x + y
}
函數(shù)(或者變量)的名稱以大寫字母開頭時,它就是已導(dǎo)出的。
函數(shù)可以返回任意數(shù)量的字符串。
func swap(x, y string) (string, string) {
return y, x
}
函數(shù)的返回值可以被命名,它們會被視作在函數(shù)頂部定義的變量,沒有參數(shù)的 return 返回已經(jīng)被命名的返回值。
func division(dividend, divisor int) (quotient, remainder int) {
quotient = dividend / divisior
remainder = dividend - quotient * divisor
return
}
函數(shù)也是值,也可以用作函數(shù)的參數(shù)和返回值。
// conpute 接受一個函數(shù)作為參數(shù)
// 調(diào)用 conpute 時傳入不同的函數(shù),返回對3和4作不同的操作的結(jié)果
func conpute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
函數(shù)的閉包 (closure)
A closure is a record storing a function together with an environment.
閉包是由函數(shù)和環(huán)境組合而成的。閉包保存和記錄了它產(chǎn)生時的外部環(huán)境——它的函數(shù)體之外的變量,并且可以訪問和修改這些變量。
在閉包實際實現(xiàn)的時候,往往通過調(diào)用一個外部函數(shù)返回其內(nèi)部函數(shù)來實現(xiàn)的。用戶得到一個閉包,也等同于得到了這個內(nèi)部函數(shù),每次執(zhí)行這個閉包就等同于執(zhí)行內(nèi)部函數(shù)。
如果外部函數(shù)的變量可見性是 local 的,即生命周期在外部函數(shù)結(jié)束時也結(jié)束的,那么閉包的環(huán)境就是封閉的。反之,那么閉包其實不再封閉,全局可見的變量的修改,也會對閉包內(nèi)的這個變量造成影響。
package main
import “fmt”
func test_1(x int) func() {
return func() {
x++
fmt.Println(x)
}
}
func test_2(x int) func() {
sum := 0
return func() {
sum += x
fmt.Println(x, sum)
}
}
func test_3(x int) func(int) int {
sum := 0
return func(y int) int {
sum += x * y
return sum
}
}
func main() {
test_1(1)()
test_2(1)()
// 每個閉包事實上有著不同的外部環(huán)境
// 即:對每個 for 循環(huán),都會新建一個 test_3()
// 所以每個閉包綁定的是不同的 sum 變量
for i := 0; i 《 5; i++ {
fmt.Printf(“%d ”, test_3(1)(i))
}
fmt.Println()
// 每個閉包的外部環(huán)境相同(tmp)
// 即 for 循環(huán)中的閉包綁定的是同一個 sum 變量
tmp := test_3(1)
for i := 0; i 《 5; i++ {
fmt.Printf(“%d ”, tmp(i))
}
fmt.Println()
}
上面的程序輸出結(jié)果是:
2
1 1
1 1
0 1 2 3 4
0 1 3 6 10
方法 (method)
Go 沒有類,不過可以為結(jié)構(gòu)體類型定義方法。方法就是一類帶特殊的接收者參數(shù)的函數(shù)。方法接收者在它自己的參數(shù)列表內(nèi),位于 func 關(guān)鍵字和方法名之間。(非結(jié)構(gòu)體類型也可以定義方法)
type Vertex struct {
X, Y float64
}
func (v Vertex) distance() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
方法并不能修改指針接收者的值。只有指針接收者的方法能夠修改接收者指向的值。(在這種情況下,方法也沒有修改接收者的值——指針的內(nèi)容,只是修改了指針指向的值,和用指針作為參數(shù)是一樣的)
在很多意義上,方法的接收者和普通的參數(shù)是一樣的。如果不使用指針。
不過,帶指針參數(shù)的函數(shù)必須接受一個指針,而以指針為接受者的方法被調(diào)用時,接受者接收者既能為值又能為指針。
package main
import “fmt”
type Vertex struct {
X, Y float64
}
func (v *Vertex) Move_1(dx, dy float64) {
v.X += dx
v.Y += dy
}
func (v Vertex) Move_2(dx, dy float64) {
v.X += dx
v.Y += dy
}
func Move_3(v *Vertex, dx, dy float64) {
v.X += dx
v.Y += dy
}
func Move_4(v Vertex, dx, dy float64) {
v.X += dx
v.Y += dy
}
func main() {
var v Vertex
v.X = 0
v.Y = 0.
v.Move_1(1, 1)
fmt.Println(v.X, v.Y)
p := &v
p.Move_1(1, 1)
fmt.Println(v.X, v.Y)
v.Move_2(1, 1)
fmt.Println(v.X, v.Y)
Move_3(&v, 1, 1)
fmt.Println(v.X, v.Y)
Move_4(v, 1, 1)
fmt.Println(v.X, v.Y)
}
上面的程序輸出結(jié)果是:
1 1
2 2
2 2
3 3
3 3
接口 (interface)
接口是一組方法簽名的集合,接口類型的變量可以保存任何實現(xiàn)了這些方法的值。
Go 語言中的接口是隱式實現(xiàn)的,也就是說,如果一個類型實現(xiàn)了一個接口定義的所有方法,那么它就自動地實現(xiàn)了該接口。沒有 implements 關(guān)鍵字。
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f 《 0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
type Abser interface {
Abs() float64
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // MyFloat 實現(xiàn)了 Abs()
a = &v // *Vertex 實現(xiàn)了 Abs()
}
指定了零個方法的接口值被稱為空接口,可以保存任何類型的值(因為每個類型都至少實現(xiàn)了零個方法)??战涌诒挥脕硖幚砦粗愋偷闹怠?/p>
在內(nèi)部,接口值可以看做包含值和具體類型的元組,類型斷言提供了訪問接口值底層具體值的方式。
package main
import “fmt”
func main() {
var i interface{} = “hello”
// 該語句斷言接口值 i 保存了具體類型 string,
// 并將其底層類型為 string 的值賦予變量 s。
// 若 i 并未保存 string 類型的值,該語句就會觸發(fā) panic。
s := i.(string)
fmt.Println(s)
// 為了判斷一個接口值是否保存了一個特定的類型,
// 類型斷言可返回兩個值:其底層值以及一個報告斷言是否成功的布爾值。
// 若 i 保存了一個 string,那么 s 將會是其底層值,而 ok 為 true。
// 否則,ok 將為 false 而 s 將為 T 類型的零值,程序并不會產(chǎn)生 panic。
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // 報錯 (panic)
fmt.Println(f)
}
上面的程序輸出結(jié)果是:
hello
hello true
0 false
panic: interface conversion: interface {} is string, not float64
。..。..
審核編輯:黃飛
-
字符串
+關(guān)注
關(guān)注
1文章
579瀏覽量
20518 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4331瀏覽量
62622 -
變量
+關(guān)注
關(guān)注
0文章
613瀏覽量
28371 -
go語言
+關(guān)注
關(guān)注
1文章
158瀏覽量
9049
原文標題:Go 的函數(shù),方法和接口
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論