Go语言中的函数特性:
函数本身可以作为值进行传递 
支持匿名函数和闭包(closure) 
函数可以满足接口 
 
1.利用函数进行链式处理 利用函数实现对list中string类型的“去go”、“去空格”、“专为大写”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package  mainimport  (	"fmt"  	"strings"  ) func  StringProcess (list []string , chain []func (string )  string )	 	for  index, str := range  list { 		result := str 		for  _, proc := range  chain { 			result = proc(result) 		} 		list[index] = result 	} } func  removePrefix (str string )  string 	return  strings.TrimPrefix(str, "go" ) } func  main () 	list := []string { 		"go scanner" , 		"go parser" , 		"go compiler" , 		"go printer" , 		"go formater" , 	} 	chain := []func (string )  string  		removePrefix, 		strings.TrimSpace, 		strings.ToUpper, 	} 	StringProcess(list, chain) 	for  _, str := range  list { 		fmt.Println(str) 	} } 
函数StringProcess(list []string, chain []func(string string)中分别将string类型与函数类型作为参数,相对C这是船新的操作。
2.匿名函数 
func(参数列表) (返回参数列表) {
 
2.1 在定义时调用匿名函数 1 2 3 func (data int ) 	fmt.Println(data) } (100 ) 
2.2 将匿名函数用作回调函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package  mainimport  "fmt" func  visit (list []int , f func (int2 int ) )	for  _, v := range  list { 		f(v) 	} } func  main () 	visit([]int {1 , 2 , 3 , 4 }, func (v int )  		fmt.Println(v) 	}) } 
visit()函数将遍历过程封装,当要获取遍历期间的切片值时,只需要给visit()传入一个回调参数即可。
2.3使用匿名函数实现封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package  mainimport  (	"flag"  	"fmt"  ) var  skillParam = flag.String("skill" , "" , "skill to perform" )func  main () 	flag.Parse() 	var  skill = map [string ]func ()  		"fire" : func ()  			fmt.Println("chicken fire" ) 		}, 		"run" : func ()  			fmt.Println("solier run" ) 		}, 		"fly" : func ()  			fmt.Println("angel fly" ) 		}, 	} 	if  f, ok := skill[*skillParam]; ok { 		f() 	} else  { 		fmt.Println("skill not found" ) 	} } 
这段代码将匿名函数作为map的value,通过命令行参数动态调用匿名函数。
2.4函数作为接口来使用 结构体实现接口 golang中的其他类型都可以实现接口,函数也可以,下文将分别对比结构体与函数实现接口的过程
type Invoker interface {
 
这个接口需要实现Call()方法,调用时会传入一个interface{}类型的变量,这种类型的变量表示任意类型的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package  mainimport  "fmt" type  Invoker interface  {	Call(interface {}) } type  Struct struct {}func  (s *Struct)  Call (p interface {}) 	fmt.Println("from struct" , p) } func  main () 	var  invoker Invoker 	s := new (Struct) 	s.Call("hello" ) 	invoker = s   	invoker.Call("hello" ) } 
输出为:
from struct hello
 
重点在invoker = s中,由于s为Struct类型的指针,且已经对应实现了Call()方法,即已经实现了Invoker接口类型,当赋值时invoker接收了一个结构体作为值。
函数体实现接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package  mainimport  "fmt" type  Invoker interface  {	Call(interface {}) } type  FuncCaller func (interface {}) func  (f FuncCaller)  Call (p interface {}) 	f(p) } func  main () 	var  invoker Invoker 	 	invoker = FuncCaller(func (v interface {})  		fmt.Println("from function" , v) 	}) 	invoker.Call("hello" ) } 
func (f FuncCaller) Call(p interface{}) {}中的Call()方法将实现Invoker中的Call()方法(还未传递),但FuncCaller的Call()方法被调用与func(interface{})无关,还需要通过f(p)手动调用函数本体。
1 2 3 invoker = FuncCaller(func (v interface {})      fmt.Println("from function" , v) }) 
这段将匿名函数转换为FuncCaller类型(函数签名才能转换),此时FuncCaller类型实现了INVOKER的Call()方法,赋值给invoker接口是成功的。
分别将函数与结构体定义为类型type 
接口传入的分别是函数和结构体 
中间部分体会需要加深  
HTTP包中的例子 HTTP包中有包含Handler接口定义,代码如下:
1 2 3 type  Handler interface {    ServeHTTP(ResponseWriter, *Request) } 
Handler用于定义每个HTTP的请求和响应的处理过程,可以使用处理函数实现接口,如下: 
 
1 2 3 4 5 type  HandlerFunc func (ResponseWriter, *Request) func  (f HandlerFunc)  ServeHTTP (w ResponseWriter, r *Request)     f(w, r) } 
要使用闭包实现默认的HTTP请求处理,可以使用http.HandleFunc()函数,函数定义: 
 
1 2 3 func  HandleFunc (pattern string , handler func (ResponseWriter, *Request) )    DefaultServeMux.HandleFunc(Pattern, handler) } 
而DefaultServeMux是ServeMux结构,拥有HandleFunc()方法,定义如下:
1 2 3 func  (mux *ServeMux)  HandlerFunc (pattern string , handler func (ResponseWriter, *Request) )    mux.Handle(pattern, HandlerFunc(handler)) } 
上面代码将外部传入的函数handler()转为HandlerFunc类型,HandlerFunc类型实现了Handler的ServeHTTP方法,底层可以同时使用各种类型来实现Handler接口进行处理。
2.5函数闭包 闭包是引用了“自由变量”的函数,被引用的自由变量和函数一同存在,即使已经离开了自由变量的环境也不会被释放或者删除,在闭包中可以继续使用这个自由变量,简单的说:
函数+引用环境=闭包
 
函数是编译期静态的概念,闭包是运行期动态的概念。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package  mainimport  "fmt" func  char ()  func (x int32 )  string 	var  str string  = "hello, "  	return  func (x int32 )  string  		str += string (x) 		return  str 	} } func  main () 	f := char() 	fmt.Println("1 " , f('a' )) 	fmt.Println("2 " , f('b' )) 	fmt.Println("3 " , f('c' )) } 
运行结果:
1  hello, a
 
个人理解,闭包其实就是利用栈的原理,通过实例化内部函数来保存局部变量。
2.6 可变参数 func function(static variables, v ...T) (r) {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package  mainimport  (	"bytes"  	"fmt"  ) func  printTypeValue (slist ...interface {})  string 	var  b bytes.Buffer 	for  _, s := range  slist { 		str := fmt.Sprintf("%v" , s) 		var  typeString string  		switch  s.(type ) { 		case  bool : 			typeString = "bool"  		case  string : 			typeString = "string"  		case  int : 			typeString = "int"  		} 		b.WriteString("value: " ) 		b.WriteString(str) 		b.WriteString(" type: " ) 		b.WriteString(typeString) 		b.WriteString("\n" ) 	} 	return  b.String() } func  main () 	fmt.Println(printTypeValue(100 , "str" , true )) } 
value: 100 type: int