【Go語言基礎【13】】函數、閉包、方法

文章目錄

  • 零、概述
  • 一、函數基礎
    • 1、函數基礎概念
    • 2、參數傳遞機制
    • 3、返回值特性
      • 3.1. 多返回值
      • 3.2. 命名返回值
      • 3.3. 錯誤處理
  • 二、函數類型與高階函數
    • 1. 函數類型定義
    • 2. 高階函數(函數作為參數、返回值)
  • 三、匿名函數與閉包
    • 1. 匿名函數(Lambda函數)
    • 2. 閉包(Closure)
  • 四、內置函數
  • 五、方法(讓go有了面向對象的特性)

零、概述

函數核心特性速查

特性說明
多返回值支持同時返回結果和錯誤(如(int, error)
可變參數通過...Type定義,本質為切片([]Type
函數類型可定義函數類型(如type FuncType func(int) bool
閉包匿名函數捕獲外部變量,保持狀態
方法綁定到結構體的函數,通過接收者參數(func (t Type) Method())定義
內置函數lenmakeappend等預定義函數,直接使用

最佳實踐

  1. 錯誤處理
    • 多返回值中優先返回錯誤(如func() (Result, error))。
    • 使用if err != nil判斷錯誤,避免忽略重要異常。
  2. 減少值拷貝
    • 傳遞大結構體時使用指針(*T),避免性能損耗。
    • 切片、map等引用類型默認傳遞指針,無需額外處理。
  3. 函數職責單一
    • 每個函數專注完成一個獨立功能,符合單一職責原則。
    • 避免函數過長(建議不超過50行),復雜邏輯拆分為子函數。

?

一、函數基礎

1、函數基礎概念

Go語言中的函數可賦值給變量、作為參數傳遞或作為返回值,極大提升了編程靈活性。

1. 函數定義語法

func 函數名(參數列表) (返回值列表) {函數體return 返回值
}
  • 參數列表:參數類型需后置,連續相同類型可合并聲明。
    func sum(x, y int) int { // x, y 均為 int 類型return x + y
    }
    
  • 返回值列表:可無返回值或多返回值(用括號包裹),支持命名返回值。
    func div(x, y int) (int, error) { // 多返回值if y == 0 {return 0, errors.New("除數不能為0")}return x / y, nil
    }
    

?

2、參數傳遞機制

1.1. 值傳遞

  • 機制:傳遞參數的副本,函數內修改不影響原始值。
  • 適用場景:小數據類型(如intstring)或無需修改原始值的場景。
    func modifyValue(x int) {x = 100 // 僅修改副本
    }
    func main() {a := 20modifyValue(a) // a 仍為 20
    }
    

1.2. 引用傳遞

  • 機制:傳遞參數的地址(通過指針*T),函數內可修改原始值。
  • 適用場景:大數據類型(如結構體)或需修改原始值的場景。
    func modifyPointer(x *int) {*x = 100 // 修改原始值
    }
    func main() {a := 20modifyPointer(&a) // a 變為 100
    }
    

1.3. 可變參數
語法:通過...Type定義可變參數,本質為切片。

func sum(nums ...int) int { // nums 類型為 []inttotal := 0for _, num := range nums {total += num}return total
}
func main() {sum(1, 2, 3) // 等價于 sum([]int{1,2,3})
}

?

3、返回值特性

3.1. 多返回值

用途:同時返回結果和錯誤(Go語言的慣用模式)。

func readFile(path string) ([]byte, error) {data, err := os.ReadFile(path)return data, err
}

3.2. 命名返回值

語法:為返回值命名,函數體可直接使用(類似變量聲明)。

func calculate(x, y int) (sum, product int) { // 命名返回值sum = x + yproduct = x * yreturn // 隱式返回 sum, product
}

3.3. 錯誤處理

丟棄返回值:用_忽略不關心的返回值。

data, _ := readFile("data.txt") // 忽略錯誤

?

二、函數類型與高階函數

1. 函數類型定義

在Go語言中,函數類型定義是指為一種特定的函數簽名創建一個自定義類型名稱。這樣可以讓具有相同簽名的函數共享同一個類型(有點面向接口開發的感覺)。

type Calculator func(int, int) int // 定義函數類型// 這些函數都符合Calculator類型的簽名
func add(x, y int) int { return x + y }
func subtract(x, y int) int { return x - y }
func multiply(x, y int) int { return x * y }
func divide(x, y int) int { return x / y }

?

例題:

package mainimport "fmt"type Calculator func(int, int) intfunc add(x, y int) int      { return x + y }
func subtract(x, y int) int { return x - y }// 使用函數類型作為參數
func calculate(calc Calculator, a, b int) int {return calc(a, b)
}// 使用函數類型作為變量
func main() {var myCalc CalculatormyCalc = addfmt.Println(myCalc(5, 3)) // 輸出: 8myCalc = subtractfmt.Println(myCalc(5, 3)) // 輸出: 2// 作為參數傳遞result := calculate(add, 10, 5)fmt.Println(result) // 輸出: 15
}

?

2. 高階函數(函數作為參數、返回值)

函數作為參數

func operate(x, y int, fn Calculator) int { // 接收函數作為參數
// 作為參數的函數,來處理參數return fn(x, y)
}
func main() {result := operate(10, 5, add) // 調用 add 函數
}

?
函數作為返回值
在Go語言中,函數可以作為返回值,這使得我們可以創建閉包。閉包是一個函數,它可以捕獲并記住其所在環境中的變量。

func makeAdder(n int) Calculator { // 返回函數return func(x int) int {return x + n}
}
func main() {add5 := makeAdder(5) // add5(3) 返回 8
}

?

三、匿名函數與閉包

1. 匿名函數(Lambda函數)

  • 無名稱函數,可直接定義和調用
 // 賦值給變量greet := func() {fmt.Println("Hello, Go!")}greet() // 調用匿名函數1. 定義:func() { ... }是一個匿名函數,因為它沒有名稱。
2. 賦值:我們將這個匿名函數賦值給變量greet。
3. 調用:通過greet()來調用這個匿名函數。// 立即執行函數表達式(IIFE)result := func(x, y int) int {return x * y}(3, 4) 1. 定義并執行:func(x, y int) int { return x * y }是一個匿名函數。
2. 立即執行:在定義后面緊跟(3, 4),這表示立即用參數34調用這個函數。
3. 結果:函數返回3 * 4的結果12,并將其賦值給變量result。

?

2. 閉包(Closure)

定義:匿名函數捕獲外部變量形成閉包,變量在閉包內保持狀態。

閉包能夠捕獲并記住其外部環境中的變量,即使在函數執行完畢后,這些變量仍然可以被訪問和修改。這使得閉包可以在不同的調用之間保持狀態,例如計數器、緩存等。

package mainimport "fmt"// adder 返回一個閉包函數,該函數捕獲了外部變量 sum
func adder() func(int) int {sum := 0 // 這是被閉包捕獲的外部變量return func(x int) int {sum += x // 每次調用時,更新并返回 sumreturn sum}
}func main() {pos := adder() // 創建一個新的閉包fmt.Println(pos(1)) // 輸出: 1fmt.Println(pos(2)) // 輸出: 3fmt.Println(pos(3)) // 輸出: 6// 創建另一個獨立的閉包neg := adder()fmt.Println(neg(-1)) // 輸出: -1fmt.Println(neg(-2)) // 輸出: -3
}

?

四、內置函數

Go語言預定義了一組內置函數,無需導入包即可使用:

函數名功能描述
len()獲取切片、字符串、通道等的長度
new()分配零值內存,返回指針(如new(int)返回*int
make()創建引用類型(切片、map、通道)并初始化
append()向切片追加元素,返回新切片
panic()觸發運行時恐慌,用于錯誤處理
recover()defer中恢復恐慌,避免程序崩潰

?

五、方法(讓go有了面向對象的特性)

在Go語言中,方法和函數的主要區別在于方法是綁定到特定類型的,而函數則是獨立的。

package mainimport ("fmt""math"
)type Circle struct {radius float64
}func (c Circle) area() float64 {return math.Pi * c.radius * c.radius
}func (c *Circle) updateRadius(r float64) {c.radius = r
}func calculateArea(radius float64) float64 {return math.Pi * radius * radius
}func main() {c := Circle{radius: 5}// 調用方法fmt.Println("Area using method:", c.area()) // 使用方法計算面積// 更新半徑c.updateRadius(10)fmt.Println("Updated area using method:", c.area())// 調用函數fmt.Println("Area using function:", calculateArea(5)) // 使用函數計算面積
}

通過方法,Go語言實現了面向對象編程的特性,使得類型可以擁有自己的行為。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/908597.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/908597.shtml
英文地址,請注明出處:http://en.pswp.cn/news/908597.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡編程之服務器模型與UDP編程

一、服務器模型 在網絡通信中,通常要求一個服務器連接多個客戶端 為了處理多個客戶端的請求,通常有多種表現形式 1、循環服務器模型 一個服務器可以連接多個客戶端,但同一時間只能連接并處理一個客戶的請求 socket() 結構體 bind() listen() …

open3D:三維點云處理

open3d 點云數據處理 爆肝5萬字??Open3D 點云數據處理基礎(Python版)_python 點云 焊縫-CSDN博客 如何用NumPy讀取和保存點云數據 - 知乎 讀取并可視化點云 np.loadtxt 從txt中讀取點集,并open3d顯示單個點云 txt內容:每行皆…

使用聯邦多軌跡圖神經網絡(GNNs)結合稀缺數據預測嬰兒腦連接|文獻速遞-深度學習醫療AI最新文獻

Title 題目 Predicting infant brain connectivity with federated multi-trajectory GNNs using scarce data 使用聯邦多軌跡圖神經網絡(GNNs)結合稀缺數據預測嬰兒腦連接 01 文獻速遞介紹 多模態影像下的嬰兒腦連接演化預測:聯邦學習與…

[特殊字符] 深入理解 Linux 內核進程管理:架構、核心函數與調度機制

Linux 內核作為一個多任務操作系統,其進程管理子系統是核心組成部分之一。無論是用戶應用的運行、驅動行為的觸發,還是系統調度決策,幾乎所有操作都離不開進程的創建、調度與銷毀。本文將從進程的概念出發,深入探討 Linux 內核中進…

第16節 Node.js 文件系統

Node.js 提供一組類似 UNIX(POSIX)標準的文件操作API。 Node 導入文件系統模塊(fs)語法如下所示: var fs require("fs") 異步和同步 Node.js 文件系統(fs 模塊)模塊中的方法均有異步和同步版本&#xff…

《探秘局域網廣播:網絡世界的 “大喇叭”》

揭開局域網廣播的神秘面紗 在當今數字化時代,網絡已成為人們生活和工作中不可或缺的一部分。從日常的網頁瀏覽、社交媒體互動,到企業級的數據傳輸、云計算應用,網絡通信無處不在。在這個龐大而復雜的網絡世界里,數據如同信息流在各個節點之間穿梭,而局域網廣播則是其中一種…

基于Ubuntu22.04安裝SVN服務器之倉庫遷移

基于Ubuntu22.04安裝SVN服務器之倉庫遷移 第一步: 停止svn服務器 第一步: 停止svn服務器 1)建議遷移的時候先把SN服務器停掉,以免操作失敗。 svnserve -d -r /usr/svn第二步:dump出svn代碼庫 1)通過dump出舊的svn服務器上的代碼…

Unity UI 性能優化終極指南 — Image篇

🎯 Unity UI 性能優化終極指南 — Image篇 🧩 Image 是什么? Image 是UGUI中最常用的基本繪制組件支持顯示 Sprite,可以用于背景、按鈕圖標、裝飾等是UI性能瓶頸的頭號來源之一,直接影響Draw Call和Overdraw &#x1…

「Java基本語法」代碼格式與注釋規范

Java代碼的基本格式 Java代碼的規范格式是編寫和維護Java程序的基礎,其中包括類定義、方法定義、代碼縮進、大括號位置等。 1.核心規則 每個Java文件必須包含一個公共類(public class),且Java源文件的文件名必須和這…

2025年AI編程工具推薦

目錄 👑 **一、全能型AI開發環境(IDE)**🛠? **二、AI代碼助手與插件**🎯 **三、垂直領域工具**🇨🇳 **四、國產工具精選**🔮 **五、創新前沿工具**?? **選型建議** 2025年&#x…

【工具使用】STM32CubeMX-FreeRTOS操作系統-信號標志、互斥鎖、信號量篇

一、概述 無論是新手還是大佬,基于STM32單片機的開發,使用STM32CubeMX都是可以極大提升開發效率的,并且其界面化的開發,也大大降低了新手對STM32單片機的開發門檻。 ????本文主要講述STM32芯片FreeRTOS信號標志、互斥鎖和信號…

ArrayList和LinkedList(深入源碼加擴展)

ArrayList 和 LinkedList 是 Java 集合框架中兩種常用的列表實現,它們在底層數據結構、性能特點和適用場景上有顯著的區別。以下是它們的詳細對比以及 ArrayList 的擴容機制。 1. ArrayList 和 LinkedList 的底層區別 (1) 底層數據結構 ArrayList: 基于動態數組(Dynamic Ar…

淺談 React Suspense

React Suspense 是 React 中用于處理異步操作的功能。它可以讓你"等待"某些操作,如數據獲取或組件加載完成,然后再渲染組件。Suspense 的核心理念是讓組件在準備好之前顯示一個備用的 UI,例如加載指示器,從而提高用戶體…

機器學習的數學基礎:線性模型

線性模型 線性模型的基本形式為: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回歸問題 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的參數估計$ \boldsymbol{\hat{\omega}}…

Linux【4】------RK3568啟動和引導順序

引導順序 RK3568 的啟動流程如下: 加電后,芯片首先執行 BootROM 中的代碼; BootROM 會嘗試從配置好的外部設備(如 NOR/NAND/eMMC/SD 卡)加載啟動程序; 如果這些設備都沒有有效的啟動代碼,Bo…

Deepseek/cherry studio中的Latex公式復制到word中

需要將Deepseek/cherry studio中公式復制到word中,但是deepseek輸出Latex公式,比如以下Latex代碼段,需要通過Mathtype翻譯才能在word中編輯。 $$\begin{aligned}H_1(k1) & H_1(k) \frac{1}{A_1} \left( Q_1 u_1(k) Q_{i1} - Q_2 u_2(k…

關于iview組件中使用 table , 綁定序號分頁后序號從1開始的解決方案

問題描述:iview使用table 中type: "index",分頁之后 ,索引還是從1開始,試過綁定后臺返回數據的id, 這種方法可行,就是后臺返回數據的每個頁面id都不完全是按照從1開始的升序,因此百度了下,找到了…

【機器學習】支持向量機實驗報告——基于SVM進行分類預測

目錄 一、實驗題目描述 二、實驗步驟 三、Python代碼實現基于SVM進行分類預測 四、我的收獲 五、我的感受 一、實驗題目描述 實驗題目:基于SVM進行分類預測 實驗要求:通過給定數據,使用支持向量機算法(SVM)實現分…

前端開發面試題總結-JavaScript篇(二)

文章目錄 其他高頻問題15、JS的數據類型有哪些16、如何判斷數組類型?17、解釋 this 的指向規則18、跨域問題及解決方案19、宏任務與微任務的區別是什么?列舉常見的宏任務和微任務。20、為什么微任務的優先級高于宏任務?設計目的是什么&#x…

硬件電路設計-開關電源設計

硬件電路設計-開關電源 電容選取設置輸出電壓電感的選取PCB布局典型電路 這里以杰華特的JW5359M 開關電源為例,介紹各個部分的功能電路。 當EN引腳電壓低于0.4V時,整個穩壓器關閉,穩壓器消耗的電源電流降至1μΑ以下 電容選取 1.C1和C25構成…