網站首頁 編程語言 正文
函數
函數的英文單詞是 Function
,這個單詞還有著功能的意思。在 Go 語言中,函數是實現某一特定功能的代碼塊。函數代表著某個功能,可以在同一個地方多次使用,也可以在不同地方使用。因此使用函數,可以提高代碼的復用性,減少代碼的冗余。
函數的聲明
通過案例了解函數的聲明有哪幾部分:
定義一個函數,實現兩個數相加的功能,并將相加之后的結果返回。
func Add(num1 int, num2 int) int { var sum int sum += num1 sum += num2 return sum }
通過案例可以發現,函數的聲明有5部分:
1、關鍵字
函數的關鍵字是 func
,聲明函數必須以 func
關鍵字開始。
2、函數名
Go
推薦使用駝峰命名的方式,和變量的命名規則一樣,首字母大寫的函數名可以在包外訪問,小寫的只能在包內訪問。
3、參數列表
參數列表中聲明了在函數體里所使用到的變量。參數列表位于函數名后面,用括號包裹著,多個參數使用逗號分隔開。
4、返回值列表
返回值為函數執行后的一個結果,上述代碼只有一個返回值,如果有多個返回值,需要用括號包裹著,返回值之間用逗號分隔開。
少數情況下,我們會聲明返回值的的名稱如 func Add(num1 int, num2 int) sum int {}
,多數情況下是不用聲明返回值的名稱的。
5、函數體
大括號內就是函數體,存放著函數的具體實現。 函數的第 3
第 4
部分可有可無,也就是說一個函數可以沒有參數和返回值。
Go 函數支持變長參數
在上面的案例中,實現的功能是對兩數求和,如果我們需要對多個數求和,但又不知道具體的數量,函數的參數該怎么聲明呢?這時可以聲明變長參數去接收多個參數。
func main() { sum := Add(1, 2, 3, 4) println(sum) // 10 } func Add(nums ...int) int { var sum int for _, num := range nums { sum += num } return sum }
變長參數作為形式參數可以接收不定的實際參數,聲明變長參數需要在類型面前加上 ...
。可變參數實際上是一個切片,可以通過 for-range
去操作。
匿名函數
通常情況下,如果一個函數只使用一次,我們就可以定義成匿名函數。
func main() { // 定義匿名函數,直接調用 result := func(num1, num2 int) int { return num1 + num2 }(1, 2) println(result) // 2、將匿名函數賦值給一個變量,由變量調用 resultFunc := func(num1, num2 int) int { return num1 + num2 } println(resultFunc(1, 2)) }
聲明函數時,不指定函數名的函數,叫做匿名函數。匿名函數可以直接調用,也可以通過賦值給變量,由變量調用。
閉包
閉包就是一個函數和其相關引用環境組合的一個整體。
import "fmt" // 返回值為一個匿名函數 func getSum() func(int) int { var sum int = 0 // 匿名函數 result := func(num int) int { sum += num return sum } return result } func main() { f := getSum() fmt.Println(f(1)) // 1 fmt.Println(f(2)) // 3 }
- 閉包的本質就是一個匿名函數,匿名函數里使用了定義它的函數(
getSum
)里面的變量sum
,就組成了閉包。 - 由上述代碼可知,匿名函數中所引用的變量
sum
會一直保存在內存中。
init 函數
每個 go
文件都可以包含一個 init
函數,它是一個初始化函數,用于進行初始化的操作。
var print = getNum() func getNum() int { println("初始化變量") return 1 } func main() { println("main...") } func init() { println("init...") }
執行結果:
初始化變量
init...
main...
- 根據執行結果可知,它們的執行順序為:全局變量 →
init
函數 →main
函數。 - 多個
go
文件都有init
函數時,執行順序為:先執行所導入的模塊的init
函數,再執行本文件的init
函數。
函數參數詳解
形式參數與實際參數
在函數聲明的地方,參數列表中的參數被稱為形式參數,簡稱形參;而在函數調用的時候所傳遞的參數被稱為實際參數,簡稱實參。舉例說明:
func main() { sum := Add(1, 2) println(sum) // 3 } func Add(num1 int, num2 int) int { var sum int sum += num1 sum += num2 return sum }
Add
后面的參數被稱為形參,而在 main
方法里,1
和 2
被稱為實參。
值傳遞
基本數據類型和數組作為實參時,默認是按 值傳遞,即進行值拷貝,在函數內修改它們的值,原來的值不會改變。舉例說明:
func main() { num1, num2 := 1, 2 Swap(1, 2) fmt.Printf("main 函數體內打印:num1: %d, num2: %d", num1, num2) } func Swap(num1 int, num2 int) { num2, num1 = num1, num2 fmt.Printf("Swap 函數體內打印:num1: %d, num2: %d\n", num1, num2) }
執行結果:
Swap 函數體內打印:num1: 2, num2: 1
main 函數體內打印:num1: 1, num2: 2
在 Swap
函數內,num1
和 num2
的值已經相互交換,但是在 main
函數里,num1
和 num2
的值沒有發生變化。
func main() { nums := [3]int{0, 1, 2} Swap(nums) fmt.Println("main 函數體內打印:nums: ", nums) } func Swap(nums [3]int) { nums[0] = 1 fmt.Println("Swap 函數體內打印:nums: ", nums) }
同樣傳遞數組,在函數內修改數組的值,原數組的值并不會改變。 前面的文章有對指針進行了介紹,指出了通過 *
操作符,可以對指針所指向的變量的值進行修改,因此如果我們想要在函數內改變外部傳過來的參數的值,函數聲明時,形參類型指定為指針類型。
func main() { num1, num2 := 1, 2 Swap(&num1, &num2) fmt.Printf("main 函數體內打印:num1: %d, num2: %d", num1, num2) } func Swap(num1 *int, num2 *int) { *num2, *num1 = *num1, *num2 fmt.Printf("Swap 函數體內打印:num1: %d, num2: %d\n", *num1, *num2) }
執行結果:
Swap 函數體內打印:num1: 2, num2: 1
main 函數體內打印:num1: 2, num2: 1
通過結果可知,使用指針變量作為形參,在函數里是可以改變外部的參數的值的。
函數是一種數據類型
在 Go
里面,函數是一種數據類型,因此函數還可以有很多用法,如創建一個函數變量、將函數作為函數的形參,將函數作為函數的返回值等。
創建函數變量
func main() { // 創建函數變量 hl := Hello fmt.Printf("%T\n", hl) // func(string) hl("cmy") } func Hello(name string) { fmt.Printf("Hello %s", name) }
創建一個函數變量 hl
,打印 hl
的類型 → func(string)
,通過 hl
變量調用函數。
作為函數的形參
import "fmt" func main() { Print("cmy", Hello) } func Hello(name string) { fmt.Printf("Hello %s", name) } func Print(name string, f func(string)) { f(name) }
定義函數 Print
,聲明兩個參數,一個參數是 name
,為 string
類型的,另一個參數是 f
,為函數類型。傳入 cmy
和 Hello
函數,由 Print
函數去執行 Hello
函數。
作為函數的返回值
import "fmt" func main() { f := Print() f() } func Print() func() { return func() { fmt.Println("Hello,World!") } }
通過Print
函數返回一個匿名函數函數,這個匿名函數的功能是輸出 Hello,World!
,使用 f
變量接收這個函數并調用。
基于函數自定義類型
type AddHandleFunc func(num1, num2 int) int func main() { sum := GetSum(1, 2, Add) println(sum) } func Add(num1, num2 int) int { return num1 + num2 } func GetSum(num1, num2 int, handleFunc AddHandleFunc) int { return handleFunc(num1, num2) }
基于函數 func(num1, num2 int) int
自定義一個類型 AddHandleFunc
,將它聲明為 GetSum
的形參,然后調用 GetSum
時,因為 Add
函數和 AddHandleFunc
是等價的,因此可以將 Add
當做實參傳進去。
小結
本文對函數的聲明進行介紹,根據一個案例了解了其組成的5部分。然后介紹了其一些特點如支持變長參數、傳遞參數時,實參按值傳遞等,最后根據函數在Go中是一種數據類型的特點,說明了其一些特別用法。
原文鏈接:https://juejin.cn/post/7171068063021400100
相關推薦
- 2023-02-25 Golang合并yaml文件過程逐步講解_Golang
- 2022-04-19 asp.core?同時兼容JWT身份驗證和Cookies?身份驗證兩種模式(示例詳解)_實用技巧
- 2022-05-04 Jupyter?notebook運行后打不開網頁的問題解決_python
- 2022-10-17 Nginx中root與alias區別講解_nginx
- 2022-10-21 golang?一次性定時器Timer用法及實現原理詳解_Golang
- 2022-09-30 python語言中pandas字符串分割str.split()函數_python
- 2022-05-20 flume的負載均衡load balancer
- 2023-02-03 C++中為何推薦要把基類析構函數設置成虛函數_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支