作者:禿禿愛健身,多平臺博客專家,某大廠后端開發(fā),個人IP起于源碼分析文章 ??。
源碼系列專欄:Spring MVC源碼系列、Spring Boot源碼系列、SpringCloud源碼系列(含:Ribbon、Feign)、Nacos源碼系列、RocketMQ源碼系列、Spring Cloud Gateway使用到源碼分析系列、分布式事務Seata使用到源碼分析系列、JUC源碼系列
基礎系列專欄:30天熟悉GO語言(建設中)
碼文不易,如果感覺博主的文章還不錯,請點贊??、收藏 ??支持一下博主哇 ??
聯(lián)系方式:Saint9768,加我進技術交流群,一起學習進步??、freedom????
一、前言
Go系列文章:
- GO開篇:手握Java走進Golang的世界
- 2 Go開發(fā)環(huán)境搭建、Hello World程序運行
- 3 Go編程規(guī)約和API包
- 4 Go的變量、常量、運算符
- 5 Go 基本數(shù)據(jù)類型
- 6 Go 復雜數(shù)據(jù)類型之指針
- 7 Go流程控制之分支結構if、switch
- 8 Go流程控制之循環(huán)結構for range、goto、break、continue
Go專欄傳送鏈接:https://blog.csdn.net/saintmm/category_12326997.html
二、函數(shù)
1、函數(shù)簡介
1)函數(shù)是什么?
函數(shù)是一個基本的代碼塊,是用于完成某一功能的程序指令集;可以對特定的功能進行提取,形成一個代碼片段,這個代碼片段即函數(shù)。
我們可以通過函數(shù)劃分不同的功能,邏輯上每個函數(shù)執(zhí)行的是指定的任務。
2)為什么要使用函數(shù)?
提高代碼的復用性,減少代碼的冗余,提高代碼的可維護性。
3)函數(shù)的特點?
- 支持可變參數(shù)
- 支持多返回值
- 支持匿名函數(shù)
- 函數(shù)也是一種數(shù)據(jù)類型,可以賦值給變量
- 不支持函數(shù)的重載(
overload
),即:一個包不能有兩個名字一樣的函數(shù) - 不支持嵌套(
nested
),即:一個包不能有兩個名字一樣的函數(shù)
2、函數(shù)的聲明和使用
1)函數(shù)聲明
函數(shù)的定義格式如下:
func name( [parameter_list] ) [return_types] {
函數(shù)體
}
- 函數(shù)
由
func關鍵字聲明,包含一個函數(shù)名、參數(shù)列表、返回值列表和函數(shù)體。- 左大括號要和func關鍵字在一行,不能另起一行。
- name:函數(shù)名稱,只能定義一次,函數(shù)名稱是唯一的,不支持重載
-
函數(shù)名命名規(guī)范:駝峰命名
- 首字母不能是數(shù)字;
- 首字母大寫該函數(shù)可以被本包文件和其它包文件使用(類似Java方法的public權限)
- 首學母小寫只能被本包文件使用,其它包文件不能使用(類似Java方法的private權限)
-
函數(shù)名命名規(guī)范:駝峰命名
- parameter_list:參數(shù)列表,指定參數(shù)類型、參數(shù)之間的順序、參數(shù)個數(shù);
- 參數(shù)類型在參數(shù)名之后,函數(shù)可以沒有參數(shù)、多個參數(shù)。
- 當多個連續(xù)的參數(shù)是同一類型,除了最后一個參數(shù)寫參數(shù)類型之外,可以參數(shù)都可以省略。
- return_types:返回類型列表,函數(shù)可以返回任意數(shù)量的返回值;
- 返回多個值時,多返回值必須用括號括起來,并以逗號隔開。
- 返回單個值時,直接相應的返回值數(shù)據(jù)類型。
- 如果函數(shù)沒有返回值,返回類型列表可以省略。
- 函數(shù)體:代碼集合。
示例1:兩數(shù)相加
func addAndFormat(num1, num2 int) int {
sum := num1 + num2
return sum
}
示例2:兩數(shù)相加,返回相加結果和結果說明
func addAndFormat(num1, num2 int, format string) (int, string) {
sum := num1 + num2
return sum, fmt.Sprintf(format, sum)
}
函數(shù)名不支持重載
1> 返回多個值 – 返回值無名稱
格式:
func name(arg1 T, arg2 T) (T, T) {
...
return r1, r2
}
特點:
- 當需要返回兩個值及以上時,返回類型用小括號包裹,逗號分隔。
- return語句中攜帶多個返回值。
2> 返回多個值 – 返回值有名稱
格式:
func name(arg1 T, arg2 T) (r1 T, r2 T) {
...
return
}
特點:
- 返回值類型指定名稱后,return語句中,可以不帶值,也可以都帶上。
- 不過,當返回值有了名稱之后,即使是只有一個返回類型,也需要用小括號包裹。
return可以不用攜帶值的原因?
- 因為等價于在返回時,初始化好了返回值;
- 以上面的格式來看,
r1
和r2
是兩個初始化的變量;- 在函數(shù)運算中,只要將返回結果存入
r1
和r2
中; - 如果不存,也可以選擇在return語句攜帶多個返回值。
- 在函數(shù)運算中,只要將返回結果存入
2)函數(shù)調(diào)用
函數(shù)可以被多次調(diào)用,在函數(shù)調(diào)用時傳遞的參數(shù)為實際參數(shù)(實參
) ,其有具體的值,用來給函數(shù)形式參數(shù)(形參
) 傳遞數(shù)據(jù)。
格式:
r1, r2 := name(param1, param2, param3)
- 格式中,r1, r2表示兩個返回值;param1, param2, param3表示三個參數(shù)。
如果接收多個值時,某個值不想使用,可以選擇使用關鍵字_
替代,表示不使用這個返回值。
r1, _ := name(param1, param2, param3)
以函數(shù)聲明中的示例2為例:
1> 返回值全部接收:
package main
import "fmt"
func main() {
format := "two num add, the result is : %d "
sum, str := addAndFormat(1, 2, format)
fmt.Println(sum)
fmt.Println(str)
}
// 兩數(shù)相加,返回相加結果和結果說明**
func addAndFormat(num1, num2 int, format string) (int, string) {
sum := num1 + num2
return sum, fmt.Sprintf(format, sum)
}
控制臺輸出:
2> 只接收一個返回值:
package main
import "fmt"
func main() {
format := "two num add, the result is : %d "
sum, _ := addAndFormat(1, 2, format)
fmt.Println(sum)
}
3、函數(shù)參數(shù)
1)值傳遞
Go語言中,基本數(shù)據(jù)類型和數(shù)組默認都是值傳遞的,即:進行值拷貝;在調(diào)用函數(shù)時將實際參數(shù)復制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進行修改時,將不會影響到原來的值。
示例:定義一個swap函數(shù),用于交換兩個int類型數(shù)據(jù)的值
package main
import "fmt"
func main() {
a := 3
b := 6
fmt.Printf("交換前 a 的值為 : %d\n", a)
fmt.Printf("交換前 b 的值為 : %d\n", b)
swap(a, b)
fmt.Printf("交換后 a 的值為 : %d\n", a)
fmt.Printf("交換后 b 的值為 : %d\n", b)
}
// 兩值交換
func swap(x, y int) int {
var temp int
temp = x
x = y
y = temp
return temp
}
控制臺輸出:
調(diào)用swap()函數(shù)交換a,b值,交換前后 a,b的值沒有改變;
所以值傳遞不會改變傳入函數(shù)實參的值,它只是復制一份數(shù)據(jù)用于函數(shù)體的執(zhí)行。
2)引用傳遞
如果希望在函數(shù)內(nèi)的變量能修改函數(shù)外的變量,可以傳入變量的地址 &
,函數(shù)內(nèi)以指針的方式操作變量;從效果來看類似引用傳遞
。
示例:
package main
import "fmt"
func main() {
a := 3
b := 6
fmt.Printf("交換前 a 的值為 : %d\n", a)
fmt.Printf("交換前 b 的值為 : %d\n", b)
swap(&a, &b)
fmt.Printf("交換后 a 的值為 : %d\n", a)
fmt.Printf("交換后 b 的值為 : %d\n", b)
}
// 兩值交換
func swap(x, y *int) int {
var temp int
temp = *x
// 將y地址上的值復制到x的地址上
*x = *y
*y = temp
return temp
}
控制臺輸出:
PS:
- 無論是值傳遞,還是引用傳遞,傳遞給函數(shù)的都是變量的副本;不過,值傳遞的是值的拷貝,引用傳遞的是地址的拷貝。
- 一般而言,地址拷貝更為高效。值拷貝的效率取決于拷貝對象的大小,對象越大,性能越低。
- map、slice、chan、指針、interface默認以引用的方式傳遞。
3)不定參數(shù) / 可變參數(shù)
不定參數(shù)傳值指:函數(shù)的參數(shù)類型固定、參數(shù)數(shù)量不固定;Go語言中可變參數(shù)本質(zhì)上是 slice
,并且該 slice 只能有一個,且必須是最后一個。
// 0個或多個參數(shù)
func myfunc1(args ...int) {
}
// 1個或多個參數(shù)
func add(a int, args…int) int {
}
// 2個或多個參數(shù)
func add(a int, b int, args…int) int {
}
- 注意:其中
args
是一個slice,我們可以通過arg[index]
依次訪問所有參數(shù),通過len(arg)
來判斷傳遞參數(shù)的個數(shù);
4、函數(shù)嵌套/遞歸使用
1)函數(shù)嵌套使用
函數(shù)中調(diào)用其他函數(shù)。
示例:test函數(shù)中調(diào)用test1函數(shù)
package main
import "fmt"
func main() {
test(3, 6)
}
func test1(a, b int) {
fmt.Println(a + b)
}
func test(a int, b int) {
fmt.Println("into function test")
test1(a, b)
}
不定參不能直接傳遞給另外一個不定參
解決措施:指定不定參arr
需要傳遞到函數(shù)testIndefiniteParam2
的數(shù)據(jù)個數(shù);
1> 指定個數(shù):
package main
import "fmt"
func main() {
testIndefiniteParam(1, 2, 3, 4)
}
// 不定參不能直接傳遞給另外一個不定參
func testIndefiniteParam(arr ...int) {
// 傳遞指定個數(shù)的數(shù)據(jù),不報錯
// 下標起始0,結束4(不包含4);僅僅為索引4之前的數(shù)據(jù)
testIndefiniteParam2(arr[0:4]...)
}
func testIndefiniteParam2(arr ...int) {
fmt.Println(arr)
}
輸出:
2> 若想要傳遞全量數(shù)據(jù),可以用下列方式:
testIndefiniteParam2(arr[0:]...)
2)遞歸函數(shù)
遞歸指函數(shù)在運行的過程中自己調(diào)用自己。
構成遞歸的條件:
- 子問題需要與原始問題是同樣的問題,且更加簡單;
- 遞歸需要出口,不能無限制地調(diào)用本身;在使用遞歸時,開發(fā)者需要設置 退出條件 ,否則遞歸將陷入無限循環(huán)。
示例:斐波那契數(shù)列(fibonacci)
package main
import "fmt"
func fibonacci(i int) int {
if i == 0 {
return 0
}
if i == 1 {
return 1
}
return fibonacci(i-1) + fibonacci(i-2)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\n", fibonacci(i))
}
}
控制臺輸出:
5、匿名函數(shù)
匿名函數(shù)指不需要定義函數(shù)名的一種函數(shù)實現(xiàn)方式,匿名函數(shù)由一個不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成;在Go語言中,函數(shù)可以像普通變量一樣被傳遞 & 使用,并且支持隨時在代碼里定義匿名函數(shù)。
構造函數(shù)時,函數(shù)沒有名稱;想調(diào)用函數(shù)時,需要把匿名函數(shù)賦值給一個變量,或 在構造時直接調(diào)用。
1)賦值給變量
func1 := func (arg1 T, arg2 T) T {
...
return r1
}
這里,func1
是一個函數(shù)類型的變量,可以直接通過func1(param1, param2)
調(diào)用函數(shù)。
示例:
package main
import "fmt"
func main() {
// 1> 匿名函數(shù)賦值給變量
func1 := func (a int, b int) int {
res := a + b
fmt.Printf("a + b = %d \n", res)
return res
}
func1(2,3)
}
2)構造時直接調(diào)用
func (arg1 T, arg2 T) T {
...
return r1
}(param1, param2)
構造函數(shù)時,函數(shù)聲明的右大括號}
后緊跟要傳遞的參數(shù)(param1, param2);這樣,構造完函數(shù)后會馬上調(diào)用。
示例:
package main
import "fmt"
func main() {
//2> 匿名函數(shù)構造時直接調(diào)用
func (a int, b int) int {
res := a + b
fmt.Printf("a + b = %d \n", res)
return res
}(2, 3)
}
6、函數(shù)類型
在Go語言中,函數(shù)也是一種數(shù)據(jù)類型,可以將函數(shù)賦值給一個變量,則該變量就是一個函數(shù)類型的變量了,通過該變量可以對函數(shù)調(diào)用。(匿名函數(shù)中有介紹)
所謂的聲明函數(shù)類型,實際就是為已存在的函數(shù)起一個別名。尤其當我們引用二方包、三方包時,可以給別人的函數(shù)取個別名。
語法:
type 自定義數(shù)據(jù)類型名 func ( [parameter_list] ) [return_types]
示例:
package main
import "fmt"
// 定義函數(shù)類型 為已存在的數(shù)據(jù)類型起別名
type funcTwoParamOneReturn func(int, int) int
func main() {
// 自定義函數(shù)類型使用
var f funcTwoParamOneReturn
f = func2
fmt.Printf("%T", f)
}
// func(int, int)
func func1(a int, b int) {
fmt.Println(a + b)
}
// func(int, int) int
func func2(x int, y int) int {
fmt.Println(x + y)
return x + y
}
對已有函數(shù)設置別名時,函數(shù)的參數(shù)類型/個數(shù)、返回值類型/個數(shù) 需要一一對應,否則會報錯;
7、Go內(nèi)置函數(shù)
和Java語言一樣,在Go語言中,有一些函數(shù)無需導包即可使用,這樣的內(nèi)置函數(shù)有15個:
- make:為切片,map、通道類型分配內(nèi)存并初始化對象。
- len:計算數(shù)組、切片、map、通道的長度。
- cap:計算數(shù)組、切片、通道的容量。
- delete:刪除 map 中對應的鍵值對。
- append:將數(shù)據(jù)添加到切片的末尾。
- copy:將原切片的數(shù)據(jù)復制到新切片中。
- new:除切片、map、通道類型以外的類型分配內(nèi)存并初始化對象,返回的類型為指針。
- complex:生成一個復數(shù)。
- real:獲取復數(shù)的實部。
- imag:獲取復數(shù)的虛部
- print:將信息打印到標準輸出,沒有換行。
- println:將信息打印到標準輸出并換行。
- close:關閉通道。
- panic:觸發(fā)程序異常。
- recover:捕捉 panic 的異常信息,必須卸載defer相關的代碼塊中。
- defer將在后面的文章中介紹
三、總結
本文介紹了函數(shù)的一些基本概念,比如:函數(shù)是什么?為什么要使用函數(shù)?函數(shù)的特點?怎么聲明一個函數(shù)?如何調(diào)用一個函數(shù)?嵌套函數(shù)是什么?匿名函數(shù)怎么聲明使用?Go中內(nèi)置函數(shù)有哪些?
對比Java來看
和Java語言一樣:
- 基礎類型都是按值傳遞,復雜類型都是按引用傳遞;
*Go中基礎類型如需按引用傳遞,需要使用指針。 - 都可以丟棄返回值。Go中使用關鍵字
_
接收返回值用于丟棄,Java直接不用變量接方法的返回。
和Java語言不同的是:
- Go中返回值可以有多個,Java中多個值需要封裝到實體或map返回;
- Go中的函數(shù)不支持重載,而Java方法可以重載;
Java中的方法定義:文章來源:http://www.zghlxwxcb.cn/news/detail-495854.html
訪問修飾符 返回值類型 方法名(參數(shù)1類型 參數(shù)1,參數(shù)2類型 參數(shù)2...) {
return 返回值;
}
Go中的函數(shù)定義:文章來源地址http://www.zghlxwxcb.cn/news/detail-495854.html
func 函數(shù)名(變量1 變量類型,變量2 變量2類型...) (返回值1 類型1,返回值2 類型2...) {
return;
}
到了這里,關于【30天熟悉Go語言】9 Go函數(shù)全方位解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!