日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Golang——秒懂函数、参数、可变参数、匿名函数、回调函数、内置函数

發布時間:2025/3/15 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang——秒懂函数、参数、可变参数、匿名函数、回调函数、内置函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

函數:

函數是結構化編程的最小模塊單元。它將復雜的算法過程分解為若干較小任務,隱藏相關 細節,使得程序結構更加清晰,易于維護。函數被設計成相對獨立,通過接收輸入參數完成一段算法指令,輸出或存儲相關結果。因此,函數還是代碼復用和測試的基本單元。
關鍵字func用于定義函數

  • 函數必須先定義,后調用,定義的過程成為函數定義,
  • 函數創建后并不是直接可以運行的,需要手動使用后,才執行,該過程成為函數調用

Go函數特點:

  • 無需前置聲明
  • 不支持命名嵌套定義(nested)
  • 不支持同名函數重載(overload)
  • 不支持默認參數
  • 支持可變參數
  • 支持多返回值
  • 支持命名返回值
  • 支持匿名函數和閉包

函數只能判斷是否為nil,不支持其他比較操作

func a() {} func b() {} func main() {println(a == nil)println(a == b) // 無效操作:a == b (func can only be compared to nil }

參數:

函數傳參都是值傳遞,實參將自己的地址值拷貝一份給形參。如果參數是引用類型,那么就會改變實參的值(A棧幀修改B棧幀的值)

定義格式:

參數:由數據類型和變量名組成 數據類型 變量名
例: int a

func 函數名(參數1 數據類型,參數2 數據類型...) {}

普通格式調用:

函數名(參數1,參數2)

函數值格式調用:

變量 := 對象.函數名

函數表達式格式調用:

變量 := 類名.函數名

函數調用時,參數的數量與類型必須與函數定義中的設置相匹配,否則程序將報錯。函數的返回值通常會使用變量接收,否則該返回值將無意義

演示:

func main() {person := Person{24}// 普通格式person.show()// 函數值格式p1 := person.showp1()// 函數表達式格式p2 := (*Person).showp2(&person) }type Person struct {age int }

不支持有默認值的可選參數,不支持命名實參。調用時必須按簽名順序傳遞指定類型和數量的實參,就算以“_”命名也不能忽略。參數列表中,相鄰的同類型參數可合并

func main() {test(1, 2, "abc") // 報錯: not enough arguments in call to test 給bool變量賦值就可以了 }func test(x, y int, s string, _ bool) *int {return nil }

參數可視作函數的局部變量,因此不能在相同層次定義同名變量

func add(x, y int) int {x := 100 // 錯誤:':=' 的左側沒有新變量var y int // 錯誤:未使用的變量 'y'return x + y }

不管是指針、引用類型,還是其他類型參數,都是值拷貝傳遞,無非是拷貝目標對象,還是拷貝指針自身而已。在函數調用時,會為形參和返回值分配內存空間, 并將實參數據拷貝到形參內存。

func main() {a := 0x100p := &aprintln(&p, p) //輸出實參p的地址。test(p) }func test(x *int) {println(&x, x) //輸出形參x的地址。 }

輸出:
從輸出結果可以看出,盡管實參和形參都指向同一目標,但指針自身依然被復制。

0x1400006cf60 0x1400006cf50 0x1400006cf58 0x1400006cf50

要實現傳出參數,通常建議使用返回值。當然,二級指針也是常用的手法

func main() {var p *inttest(&p)println(*p) }func test(p **int) {x := 100 * p = &x }

如果函數參數過多,建議將其重構為一個復合類型參數,也算是變向實現可選參數和命名實參功能

func main() {opt := newOption()opt.port = 8085server(opt) }type serverOption struct {address stringport intpath stringtimeout time.Durationlog *log.Logger }func newOption() *serverOption {return &serverOption{address: "0.0.0.0",port: 8080,path: "/var/test",timeout: time.Second * 5,log: nil,} }func server(option *serverOption) {}

形參和實參:

形參是指函數定義中的參數,實參則是函數調用時所傳遞的參數。形參類同函數局部變量,而實參則函數外部對象,可以是常量、變量、表達式或函數等。

形參:

函數定義中的參數,顧名思義就是只有一個形式,沒有具體的數值
等同于變量定義格式,例如:var num int

實參:

函數調用中的參數,顧名思義就是有實際的參數數值
等同于使用變量或常量,例如:var num int =10

傳遞的形參即使在函數中操作,也不會影響原來的數據值

func main() {a, b := 1, 2Demo12(a, b)fmt.Println("main:", a, b) //main: 1 2 } func Demo12(a, b int) {a, b = b, afmt.Println("Demo12:", a, b) //Demo12: 2 1

可變參數(不定參數):

寫函數的時候如果不知道形參長度,可以使用可變參數傳遞
變參本質上就是一個slice,它只能接收相同類型的參數值,且必須放在參數列表的最后

圖解:

演示:

func main() {//Demo01(1)Demo02(1, 2, 3, 4, 5) }func Demo01(num int) {for i := 0; i < num; i++ {fmt.Println("test")} }func Demo02(num ...int) {for i := 0; i < len(num); i++ {fmt.Println(num[i])} }// 如果可變參數和其它參數一起作為形參時,可變參數需要放在后面 func Demo03(aaa int , num ...int) {for i := 0; i < len(num); i++ {fmt.Println(num[i])} }

變參是slice,那么參數復制的僅是slice struct自身,不包括底層數組,因此我們可以修改原數據。如果需要,可使用內置函數copy復制slice數據

func test(a ...int) {for i := range a {a[i] += 100} } func main() {a := []int{10, 20, 30}test(a...)fmt.Println(a) }

返回值:

函數可以有返回值,也可以有返回值,也可以定義多個返回值。使用return關鍵字定義
如果沒有定義返回值,但是寫了return,那么就相當于終止了函數,跳出循環的意思

方式一:

func main() {// 定義變量接收返回值并執行打印r := Demo06(1, 2)println(r) }// 要在參數后面加上返回值的數據類型 func Demo06(a int, b int) int {// 將a+b的結果賦值給sum并返回,需要在函數里再定義返回值sum := a + breturn sum }

方式二:

func main() {// 定義變量接收返回值并執行打印r := Demo07(1, 2)println(r) }// 要在參數后面加上返回值和返回值的數據類型,不需要在函數里再定義返回值 func Demo07(a int, b int) (sum int) {sum = a + breturn sum }

方式三:

func main() {// 定義變量接收返回值并執行打印r := Demo08(1, 2)println(r) }// 要在參數后面加上返回值和返回值的數據類型,不需要在函數里再定義返回值 func Demo08(a int, b int) (sum int) {sum = a + b// 如果在函數上已經指定了返回值,在函數中可以省略返回值,直接returnreturn }

函數返回多個返回值:

func main() {// 定義變量接收返回值a, b := Demo09()fmt.Println("a = ", a, "\n b = ", b) }// 在函數上只寫返回值類型,在函數中寫返回值 func Demo09() (int, int) {a := 1b := 2// 返回兩個變量的值return a, b }

有返回值的函數,必須有明確的return終止語句

func test(x int) int {if x > 0 {return -1} else if x < 0 {return -1} } // 錯誤:missing return at end of function

特例情況是panic,或者無break的死循環

func test(x int) int {for {break} }

借鑒自動態語言的多返回值模式,讓函數得以返回更多狀態,尤其是error模式。

import "errors" func div(x, y int) (int, error) { //多返回值列表必須使用括號。if y == 0 {return 0, errors.New("division by zero")}return x / y, nil }

相同類型的多返回值可用作調用實參,或直接返回

func main() {log(test()) //多返回值直接用作實參。 } func test() (int, error) {return div(5, 0) //多返回值直接用作return結果。 }func div(x, y int) (int, error) {if y == 0 {return 0, errors.New("division by zero")}return x / y, nil }func log(x int, err error) {fmt.Println(x, err) }

返回值命名:

從這個簡單的示例就可看出,命名返回值讓函數聲明更加清晰,同時也會改善幫助文檔和 代碼編輯器提示。

func paging(sql string, index int) (count int, pages int, err error) {}

命名返回值和參數一樣,可當做函數局部變量使用,最后由return隱式返回

func div(x, y int) (z int, err error) {if y == 0 {err = errors.New("division by zero")return}z = x / yreturn // 相當于 “return z, err”。 }

只是這些特殊的局部變量會被不同層級的同名變量遮蔽,造成潛在錯誤。好在編譯器會自動檢查此類狀況,只需改為顯式return返回即可

func add(x, y int) (z int) {{z := x + y //新定義的同名局部變量,同名遮蔽。return // 錯誤:z is shadowed during return (改成 “return z” 即可)}return }

除遮蔽外,我們還必須對全部返回值命名,否則編譯器會稀里糊涂

func test() (int, s string, e error) {return 0, "", nil // 錯誤:cannot use 0 (type int) as type string in return argument }

函數重寫:

子類中出現與父類一模一樣的函數時,會使用就近原則,子類優先使用子類的函數,要想通過子類的對象調用父類的函數,需要使用子類對象.父類.函數名

函數重寫的應用場景:

當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的函數,這樣,即沿襲了父類的功能,又定義了子類特有的內容

演示:

func main() {stu := Student{}stu.show() // 子類的Show函數stu.Person.show() // 父類的Show函數 }type Person struct {age int }type Student struct {Personname stringage intscore float64 }func (student Student) show() {fmt.Println("子類的Show函數") }func (person *Person) show() {fmt.Println("父類的Show函數") }

匿名函數:

匿名函數是指沒有定義名字符號的函數
匿名函數除沒有名字外,其他和普通函數完全相同。最大的區別是,我們可在函數內部定義匿名函數,形成類似嵌套函數的效果。匿名函數可直接調用,保存到變量,作為參數或返回值

格式:

func(形參) {函數體}(實參)

直接執行:

func main() {func(s string) {fmt.Println(s)}("我是實參,上面的s,是形參,我會被打印不") }

有返回值匿名函數:

func main() {add := test()println(add(1, 2)) }func test() func(int, int) int {return func(x, y int) int {return x + y} }

作為第一類對象,不管是普通函數,還是匿名函數都可作為struct字段,或通過channel傳遞

func testStruct() {type calc struct {mul func(x, y int) int}x := calc{mul: func(x, y int) int {return x * y},}println(x.mul(2, 3)) } func testChannel() {c := make(chan func(int, int) int, 2)c <- func(x, y int) int {return x + y}println((<-c)(1, 2)) }

回調函數:

本質就是函數類型的指針,通過指針,在特定位置,滿足條件后,系統會自動調用函數。

普通函數調用格式:

func aaa(){}func main(){aaa()// 普通函數是通過函數名+括號調用的 }

回調函數調用格式:

func handler(w http.ResponseWriter, r *http.Request) {}func main(){http.HandleFunc("/itzhuzhu", handler)// 只需要將函數名傳入即可 }

內置函數:

len:用來計算長度的,string、arr、slice、map、channel都可以
new:用來分配值內存的,int、float32、struct返回值是指針
make:用來分配引用類型內存的,slice、map、channel

func main() {//num := 100num2 := new(int)*num2 = 100fmt.Printf("num2的類型:%T,num2的值:%v,num2的內存地址:%v,num2指向地址存儲的數據:%v", num2, num2, &num2, *num2) }

直接定義變量的流程是:開辟內存空間->將數據存儲到內存空間
適用new定義變量的流程是:開啟指針內存空間->指向數據的內存地址

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Golang——秒懂函数、参数、可变参数、匿名函数、回调函数、内置函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。