
人永遠(yuǎn)都無法知道自己該要什么,因?yàn)槿酥荒芑钜淮危炔荒苣盟笆老啾?,也不能在來生加以修正。沒有任何方法可以檢驗(yàn)?zāi)姆N抉擇是好的,因?yàn)椴淮嬖谌魏伪容^。一切都是馬上經(jīng)歷,僅此一次,不能準(zhǔn)備。from 《不能承受的生命之輕》
引用于:http://wufazhuce.com/one/1380
函數(shù)在Go語言中應(yīng)該是最頻繁使用的類型了,所以把Go語言定義為函數(shù)式編程語言,個(gè)人認(rèn)為也是一種正確的解釋。函數(shù)在Go中既有類似JS語言的用法,也有C、JAVA這種語言的身影。
和JS語言對(duì)比,函數(shù)有以下特性:
- 普通函數(shù):作為一個(gè)普通方法使用。
- 變長參數(shù):函數(shù)可以接收可變數(shù)目的參數(shù),這在JAVA里面也有類似用法。
- 閉包函數(shù):JS中常用的一種模式,便于維護(hù)一些特殊作用域的變量等用法。
- 對(duì)象中的方法:JS中類面向?qū)ο蟮囊环N寫法。
和C語言對(duì)比,函數(shù)有以下特性:
- 多返回值:函數(shù)可以返回多個(gè)不同類型的結(jié)果。
Go自身定義的函數(shù)特性:
- 巧用return:合理的利用return中斷程序邏輯,會(huì)使代碼顯得更簡潔易懂。
- 作為參數(shù)傳遞:作為回調(diào)函數(shù)來說,更好的規(guī)范了回調(diào)函數(shù)引用的規(guī)范性。
- 值傳遞:變量作為參數(shù)傳遞給函數(shù)時(shí),默認(rèn)是值傳遞,只是變量的一個(gè)拷貝,即副本。函數(shù)內(nèi)部只是對(duì)變量副本的操作,不會(huì)影響到實(shí)際變量本身。
普通函數(shù)、多返回值
// 普通函數(shù),不帶參數(shù)
func generalFun() {
fmt.Println("普通函數(shù)")
}
// 普通函數(shù),帶參數(shù)
func generalFun1(i int, str string) {
fmt.Printf("i=%d str=%s\n", i, str)
}
// 普通函數(shù),帶參數(shù)和返回一個(gè)結(jié)果
func generalFun2(i int, str string) string {
tempStr := strconv.Itoa(i) + str
return tempStr
}
// 普通函數(shù),帶參數(shù)和返回多個(gè)結(jié)果,需要用括號(hào)包含所有返回類型
func generalFun3(i int, str string) (int, string) {
tempStr := strconv.Itoa(i) + str
tempI := i + i
return tempI, tempStr
}
上面示例中的普通函數(shù)用法,作為對(duì)象的方法也是同樣支持。
變長參數(shù)
格式:paramName ...type:可理解為函數(shù)可以接收type類型的可變參數(shù),參數(shù)名稱為paramName,在函數(shù)內(nèi)部可把paramName理解為類似slice類型的參數(shù)值??捎?code>for _, val := range paramName遍歷傳遞進(jìn)來的多個(gè)參數(shù)。
1、第一種用法:知道可變參數(shù)的類型時(shí):
func myfun(prefix string, who ...string) {
//獲取可變參數(shù)的長度
fmt.Println(len(who))
for _, val := range who {
fmt.Println(prefix, val)
}
}
func Test_fun_Sample01(t *testing.T) {
myfun("hello:", "Joe", "Anna", "Eileen")
}
Test_fun_Sample01 測試用例執(zhí)行結(jié)果:
hello: Joe
hello: Anna
hello: Eileen
2、第二種用法:不知道可變參數(shù)的類型時(shí):
如果一個(gè)變長參數(shù)的類型沒有被指定,則可以使用默認(rèn)的空接口 interface{},這樣就可以接受任何類型的參數(shù)。該方案不僅可以用于長度未知的參數(shù),還可以用于任何不確定類型的參數(shù)??墒褂?code>for-range循環(huán)以及switch結(jié)構(gòu)對(duì)每個(gè)參數(shù)的類型進(jìn)行判斷
type Person struct {
name string
}
func test8(values ...interface{}) {
for _, val := range values {
switch v := val.(type) {
case int:
fmt.Println("val type is int ", v)
case float64:
fmt.Println("val type is float ", v)
case string:
fmt.Println("val type is string ", v)
case bool:
fmt.Println("val type is bool ", v)
case Person:
fmt.Println("val type is Person ", v.name)
case *Person:
fmt.Println("val type is *Person ", v.name)
default:
fmt.Println("val type is unknow ", v)
}
}
}
func Test_test8(t *testing.T) {
temp_int := 1
temp_float := 5.6
temp_string := "hello"
temp_bool := true
temp_person1 := &Person{name: "jack"}
temp_person2 := Person{name: "rose"}
var temp_float32 float32 = 6.6
test8(temp_int, temp_float, temp_string, temp_bool, temp_person1, temp_person2, temp_float32)
}
運(yùn)行結(jié)果:
val type is int 1
val type is float 5.6
val type is string hello
val type is bool true
val type is *Person jack
val type is Person rose
val type is unknow 6.6
示例中需要注意的兩個(gè)地方:
-
float默認(rèn)定義的類型為float64。 -
struct要區(qū)分傳遞的參數(shù)是 Person 類型的結(jié)構(gòu)體變量,還是 Person 類型的指針變量。
巧用return
1、第一種用法:無返回值函數(shù),在內(nèi)部任何程序執(zhí)行片段使用return ,直接會(huì)跳出該函數(shù),return下面的程序片段都不會(huì)再執(zhí)行。
func fun_return() {
for i := 0; i < 10; i++ {
fmt.Printf("%v ", i)
if i == 3 {
return
}
}
} //0 1 2 3
2、第二種用法:有返回值函數(shù),在內(nèi)部任何程序執(zhí)行片段使用return,它下面的程序片段都不會(huì)再執(zhí)行,但是程序結(jié)尾必須以return結(jié)束,否則程序報(bào)錯(cuò)。
func fun_return() int {
for i := 0; i < 10; i++ {
fmt.Printf("%v ", i)
if i == 3 {
return
}
}
return i
} //0 1 2 3
上面兩個(gè)示例,執(zhí)行結(jié)果一樣,但是唯一不同的就是有返回值函數(shù)程序最后必須有
return。
值傳遞、引用傳遞
任何時(shí)候,如果要同步改變函數(shù)外聲明的變量的值時(shí),都要優(yōu)先考慮用指針傳遞,即占用內(nèi)存空間少,又執(zhí)行速度快。
基本類型的參數(shù)傳遞
func test3(str string) {
str = "go"
fmt.Printf("str=%s", str)
}
func test4(str *string) {
*str = "go"
fmt.Printf("str=%s", *str)
}
func Test_test3(t *testing.T) {
temp := "hello"
test3(temp)
fmt.Println(" temp=", temp) //str=go temp= hello
test4(&temp)
fmt.Println(" temp=", temp) //str=go temp= go
}
struct類型的參數(shù)傳遞,及對(duì)象傳遞
type Person struct {
name string
}
// 傳遞Person struct類型的變量
func test5(p Person) {
p.name = "go" // 此時(shí)的p為參數(shù)副本
fmt.Printf("Person.name = %s", p.name)
}
// 傳遞指向Person struct類型的的變量地址
func test6(p *Person) {
p.name = "go"
fmt.Printf("Person.name = %s", p.name)
}
func Test_test5(t *testing.T) {
p := Person{"hello"}
test5(p)
fmt.Println(" p.name=", p.name) //Person.name = go p.name= hello
test6(&p)
fmt.Println(" p.name=", p.name) //Person.name = go p.name= go
p1 := new(Person)
p1.name = "jack"
test6(p1)
fmt.Println(" p1.name=", p1.name) //Person.name = go p1.name= go
}