您好,登錄后才能下訂單哦!
Go語言中定義函數(shù)使用fun關(guān)鍵字,具體格式為
func 函數(shù)名(參數(shù))(返回值){
函數(shù)體
}
其中:
1.函數(shù)名:由字母,數(shù)字,下劃線組成。但函數(shù)名的第一個字母不能是數(shù)字。在同一個包內(nèi),函數(shù)名不能重名。
2.參數(shù):參數(shù)由變量名和變量類型組成。
3.返回值:可以只寫返回值類型,多個返回值必須用()包裹,并用,分隔。
4.函數(shù)體:實(shí)現(xiàn)指定功能的代碼塊。
定義一個求兩個數(shù)和的函數(shù):
func intSum(x int, y int) int {
return x + y
}
函數(shù)的參數(shù)和返回值是可選的,我們也可以不傳參也沒有返回值。
func sayHello() {
fmt.Println("Hello vita")
}
定義了函數(shù)后,可以通過 函數(shù)名()的方式調(diào)用函數(shù)。
調(diào)用有返回值的函數(shù)時,可以不接收返回值。
package main
import "fmt"
func sayHello(){
fmt.Println("hello vita")
}
func main() {
sayHello()
}
結(jié)果:
hello vita
函數(shù)的參數(shù)中如果相鄰變量的類型相同,則可以省略類型。
package main
func intSum(x,y int)int{
return x+y
}
func main() {
intSum(1,2)
}
intSum函數(shù)有兩個參數(shù),x,y的類型都是int,因此可以省略x的類型,因?yàn)閥后面有類型說明。
可變參數(shù)即參數(shù)數(shù)量不固定。Go語言中的可變參數(shù)通過在參數(shù)后面加...來標(biāo)識。
注意:可變參數(shù)通常要作為函數(shù)的最后一個參數(shù)。
package main
import "fmt"
func intSum(x ...int)int{
fmt.Println(x)//x是一個切片
sum:=0
for _,value :=range x{
sum+=value
}
return sum
}
func main() {
sum1 := intSum(1,2,3,4,5)
sum2 := intSum(1,2,3,4,5,6,7)
sum3 := intSum(1,2,3,4,5,6,7,8,9)
fmt.Println(sum1)
fmt.Println(sum2)
fmt.Println(sum3)
}
結(jié)果:
[1 2 3 4 5]
[1 2 3 4 5 6 7]
[1 2 3 4 5 6 7 8 9]
15
28
45
可變參數(shù)放在固定參數(shù)的后面
package main
import "fmt"
func intSum(x int,y ...int)int{
sum:=x
for _,value :=range y{
sum+=value
}
return sum
}
func main() {
sum1 := intSum(1,2,3,4,5)
sum2 := intSum(1,2,3,4,5,6,7)
sum3 := intSum(1,2,3,4,5,6,7,8,9)
fmt.Println(sum1)
fmt.Println(sum2)
fmt.Println(sum3)
}
結(jié)果:
15
28
45
Go語言中支持多返回值,函數(shù)如果有多個返回值,必須使用()把所有返回值包裹起來。
package main
func calc(x,y int)(int,int){
sum :=x+y
sub:=x-y
return sum,sub
}
func main() {
calc(3,2)
}
函數(shù)定義時,可以給返回值命名,并在函數(shù)體中直接使用這些變量,最后通過return關(guān)鍵字返回。
package main
func calc(x,y int)(sum int,sub int){
sum =x+y
sub=x-y
return
}
func main() {
calc(3,2)
}
全局變量是定義在函數(shù)外部的變量,他在程序整個運(yùn)行周期內(nèi)都有效。在函數(shù)中可以訪問到全局變量。
package main
import "fmt"
var num int64=100
func testGlobalVar(){
fmt.Printf("num=%d\n",num)
}
func main() {
testGlobalVar() //num=100
}
函數(shù)內(nèi)定義的變量,無法在函數(shù)外使用。
func testLocalVar() {
//定義一個函數(shù)局部變量x,僅在該函數(shù)內(nèi)生效
var x int64 = 100
fmt.Printf("x=%d\n", x)
}
func main() {
testLocalVar()
fmt.Println(x) // 此時無法使用變量x
}
如果局部變量和全局變量重名,優(yōu)先訪問局部變量。
package main
import "fmt"
//定義全局變量num
var num int64 = 10
func testNum() {
num := 100
fmt.Printf("num=%d\n", num) // 函數(shù)中優(yōu)先使用局部變量
}
func main() {
testNum() // num=100
}
語句塊中定義的變量,通常我們會在if條件判斷,for循環(huán),switch語句上使用這種定義變量的方式。
func testLocalVar2(x, y int) {
fmt.Println(x, y) //函數(shù)的參數(shù)也是只在本函數(shù)中生效
if x > 0 {
z := 100 //變量z只在if語句塊生效
fmt.Println(z)
}
//fmt.Println(z)//此處無法使用變量z
}
for循環(huán)語句中定義的變量,也只在for語句塊中生效
func testLocalVar3() {
for i := 0; i < 10; i++ {
fmt.Println(i) //變量i只在當(dāng)前for語句塊中生效
}
//fmt.Println(i) //此處無法使用變量i
}
我們可以使用type關(guān)鍵字定義一個函數(shù)類型,具體格式如下:
type calculation func(int, int) int
上面語句定義了一個calculation類型,它是一種函數(shù)類型,接收兩個int參數(shù),返回值類型為int。
簡單的說,凡是滿足這個條件的函數(shù)都是calculation類型的函數(shù),例如下面的add和sub是calculation類型。
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
add和sub都能賦值給calculation類型的變量。
var c calculation
c = add
我們可以聲明函數(shù)類型的變量并且為該變量賦值:
func main() {
var c calculation // 聲明一個calculation類型的變量c
c = add // 把a(bǔ)dd賦值給c
fmt.Printf("type of c:%T\n", c) // type of c:main.calculation
fmt.Println(c(1, 2)) // 像調(diào)用add一樣調(diào)用c
f := add // 將函數(shù)add賦值給變量f1
fmt.Printf("type of f:%T\n", f) // type of f:func(int, int) int
fmt.Println(f(10, 20)) // 像調(diào)用add一樣調(diào)用f
}
高階函數(shù)分為函數(shù)作為參數(shù)和函數(shù)作為返回值。
package main
import "fmt"
func add(x,y int) int {
return x+y
}
func calc(x,y int, op func(int,int) int) int{
return op(x,y)
}
func main() {
ret2 := calc(10,20,add)
fmt.Println(ret2) //30
}
package main
import (
"errors"
"fmt"
)
func add(x,y int) int {
return x+y
}
func sub(x,y int) int {
return x-y
}
func do(s string) (func(int, int) int,error) {
switch s {
case "+":
return add,nil
case "-":
return sub,nil
default:
err := errors.New("無法識別的操作符")
return nil,err
}
}
func main() {
addResult,err := do("+")
fmt.Println(addResult(1,2),err)
subResult,err := do("-")
fmt.Println(subResult(2,1),err)
informalResult,err := do(".")
fmt.Println(informalResult,err)
}
結(jié)果:
3 <nil>
1 <nil>
<nil> 無法識別的操作符
Process finished with exit code 0
函數(shù)可以作為返回值,但是在GO語言中,只能定義匿名函數(shù)。
匿名函數(shù)就是沒有函數(shù)名的函數(shù),匿名函數(shù)的定義格式如下:
func(參數(shù))(返回值){
函數(shù)體
}
匿名函數(shù)因?yàn)闆]有函數(shù)名,所以不能像普通函數(shù)那樣調(diào)用,所以匿名函數(shù)需要保存到某個變量或者作為立即執(zhí)行函數(shù)。
匿名函數(shù)多用于實(shí)現(xiàn)回調(diào)函數(shù)和閉包。
package main
import "fmt"
func main() {
//將匿名函數(shù)保存到變量
add := func(x,y int) {
fmt.Println(x+y)
}
add(10,20) //通過變量調(diào)用匿名函數(shù)
//自執(zhí)行函數(shù):匿名函數(shù)定義完加()直接執(zhí)行
func(x,y int){
fmt.Println(x+y)
}(10,20)
}
結(jié)果:
30
30
Process finished with exit code 0
閉包,在Python中,是外部函數(shù)的返回值是內(nèi)部函數(shù)的應(yīng)用,內(nèi)部函數(shù)使用了外部函數(shù)的變量,這就構(gòu)成了閉包。
在Go語言中,也是同樣的。
adder函數(shù)的返回值是一個內(nèi)部的匿名函數(shù),該匿名函數(shù)引用了外部的變量x,并且x變量在f的生命周期內(nèi)一直有效。
package main
import "fmt"
func adder() func(int) int {
var x int
return func(y int) int {
x += y
return x
}
}
func main() {
f := adder()
fmt.Println(f(10))//10
fmt.Println(f(20))//30
fmt.Println(f(30))//60
f1 := adder()
fmt.Println(f1(40))//40
fmt.Println(f1(50))//90
}
結(jié)果:
10
30
60
40
90
Process finished with exit code 0
閉包進(jìn)階示例1
package main
import "fmt"
func adder2(x int) func(int) int {
return func(y int) int {
x += y
return x
}
}
func main() {
f := adder2(10)
fmt.Println(f(10))//20
fmt.Println(f(20))//40
fmt.Println(f(30))//70
f1 := adder2(20)
fmt.Println(f1(40))//60
fmt.Println(f1(50))//110
}
結(jié)果:
20
40
70
60
110
Process finished with exit code 0
閉包進(jìn)階示例2:
package main
import (
"fmt"
"strings"
)
func makeSuffixFunc(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name,suffix){
return name + suffix
}
return name
}
}
func main() {
jpgFunc := makeSuffixFunc(".jpg")
textFunc := makeSuffixFunc(".txt")
fmt.Println(jpgFunc("test"))
fmt.Println(textFunc("test"))
}
結(jié)果:
test.jpg
test.txt
Process finished with exit code 0
閉包進(jìn)階示例3:
package main
import "fmt"
func calc(base int) (func(int) int,func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add,sub
}
func main() {
f1,f2 := calc(10)
fmt.Println(f1(1),f2(2))
fmt.Println(f1(3),f2(4))
fmt.Println(f1(5),f2(6))
}
結(jié)果:
11 9
12 8
13 7
Process finished with exit code 0
Go語言中的defer語句會將其后面跟隨的語句進(jìn)行延遲處理。
在defer歸屬的函數(shù)即將返回時,將延遲處理的語句按defer定義的逆序進(jìn)行執(zhí)行。
即先被defer的語句最后被執(zhí)行,最后被defer的語句,最先執(zhí)行。
package main
import "fmt"
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
結(jié)果:
start
end
3
2
1
Process finished with exit code 0
由于defer語句延遲調(diào)用的特性,所以defer語句能非常方便的處理資源釋放問題。比如:資源清理、文件關(guān)閉、解鎖及記錄時間等。
在Go語言的函數(shù)中,return語句在底層并不是原子操作,它分為給返回值賦值和RET指令兩步。
defer語句執(zhí)行時機(jī)就在賦值操作后,RET指令執(zhí)行前。具體如圖:
package main
import "fmt"
// 關(guān)于defer的面試題
func f1() int {
x := 5
defer func() {
x++
}()
return x // 1. 返回值=5 2. x++ 3. RET指令 ==> 5
}
func f2() (x int) {
defer func() {
x++
}()
return 5 // 1. (匯編)返回值=x(5) 2. x++ 3.(匯編)RET ==> 6
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x // 1. (匯編)返回值=y(5) 2. x++ 3.(匯編)RET ==> 5
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5 //1. (匯編)返回值=x(5) 2. x++(函數(shù)內(nèi)部的x) 3.(匯編)RET ==> 5
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}
package main
import "fmt"
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
提示:defer注冊要延遲執(zhí)行的函數(shù)時該函數(shù)所有的參數(shù)都需要確定其值
結(jié)果:
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
Process finished with exit code 0
Go語言中,目前(Go1.12)是沒有異常機(jī)制的,但是使用panic/recover模式可以處理錯誤。
panic可以在任何地方引發(fā),但是recover只有在defer調(diào)用的函數(shù)中有效。
package main
import "fmt"
func funcA() {
fmt.Println("func A")
}
func funcB() {
panic("func B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}
在程序運(yùn)行期間,funcB中引發(fā)了panic,導(dǎo)致程序崩潰,異常退出了。
這個時候,我們可以通過recover將程序恢復(fù)回來,繼續(xù)往后執(zhí)行。
package main
import "fmt"
func funcA() {
fmt.Println("func A")
}
func funcB() {
defer func() {
err := recover()
if err != nil{
fmt.Println("recover in B")
}
}()
panic("func B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}
結(jié)果:
func A
recover in B
func C
Process finished with exit code 0
注意:
1.recover()必須搭配defer使用。
2.2.defer一定要在可能引發(fā)panic的語句之前定義。
/*
你有50枚金幣,需要分配給以下幾個人:Matthew,Sarah,Augustus,Heidi,Emilie,Peter,Giana,Adriano,Aaron,Elizabeth。
分配規(guī)則如下:
a. 名字中每包含1個'e'或'E'分1枚金幣
b. 名字中每包含1個'i'或'I'分2枚金幣
c. 名字中每包含1個'o'或'O'分3枚金幣
d: 名字中每包含1個'u'或'U'分4枚金幣
寫一個程序,計算每個用戶分到多少金幣,以及最后剩余多少金幣?
程序結(jié)構(gòu)如下,請實(shí)現(xiàn) ‘dispatchCoin’ 函數(shù)
*/
var (
coins = 50
users = []string{
"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
}
distribution = make(map[string]int, len(users))
)
func main() {
left := dispatchCoin()
fmt.Println("剩下:", left)
}
package main
import (
"fmt"
"strings"
)
var (
coins = 50
users = []string{
"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth",
}
distribution = make(map[string]int, len(users))
)
func dispatchCoin() int{
count := 0
for _,value := range users{
eCount := strings.Count(strings.ToLower(value),"e")
iCount := strings.Count(strings.ToLower(value),"i")
oCount := strings.Count(strings.ToLower(value),"o")
uCount := strings.Count(strings.ToLower(value),"u")
personCount := eCount*1+iCount*2+oCount*3+uCount*4
fmt.Printf("Pserson:%s,coins:%d\n",value,personCount)
count += personCount
}
return coins-count
}
func main() {
left := dispatchCoin()
fmt.Println("剩下:", left)
}
結(jié)果:
Pserson:Matthew,coins:1
Pserson:Sarah,coins:0
Pserson:Augustus,coins:12
Pserson:Heidi,coins:5
Pserson:Emilie,coins:6
Pserson:Peter,coins:2
Pserson:Giana,coins:2
Pserson:Adriano,coins:5
Pserson:Aaron,coins:3
Pserson:Elizabeth,coins:4
剩下: 10
Process finished with exit code 0
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。