装饰器, 函数式编程
普通的装饰器
package main_test
import (
"fmt"
"testing"
)
func decorator(f func(s string)) func(s string){
return func(s string){
fmt.Printf("started")
f(s)
fmt.Printf("ended")
}
}
func Hello(s string){
fmt.Print("hello")
}
func TestDecorator(t *testing.T){
//decorator(Hello)("s")
hello := decorator(Hello)
hello("s")
}
时间装饰器
package main_test
import (
"fmt"
"reflect"
"runtime"
"testing"
"time"
)
type SumFunc func(int64, int64) int64
// 使用了 Go 语言的反射机器来获取函数名
func getFuncName(i interface{}) string{
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
func timeSumFunc(f SumFunc) SumFunc{
return func(start, end int64) int64{
defer func(t time.Time){
fmt.Printf("Time (%s) spend %v", getFuncName(f), time.Since(t))
}(time.Now())
return f(start, end)
}
}
func Sum1(start, end int64) int64 {
var sum int64 = 0
sum = 0
if start > end {
start, end = end, start
}
for i := start; i <= end; i++ {
sum += i
}
return sum
}
func Sum2(start, end int64) int64 {
if start > end {
start, end = end, start
}
return (end - start + 1) * (end + start) / 2
}
func TestTimeDecorator(t *testing.T){
sum1 := timeSumFunc(Sum1)
sum2 := timeSumFunc(Sum2)
t.Log(sum1(-100, 10000))
t.Log(sum2(-1000, 100000))
}
多个修饰器的 Pipeline
package main_test
import (
"log"
"net/http"
"strings"
"testing"
)
type HttpHandlerDecorator func(handlerFunc http.HandlerFunc) http.HandlerFunc
func Handler(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc{
for i := range decors{
d := decors[len(decors) - 1 - i]
h = d(h)
}
return h
}
func hello(w http.ResponseWriter, r *http.Request) {
log.Printf("Recieved Request %s from %s\n", r.URL.Path, r.RemoteAddr)
}
func WithServerHeader(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println("--->WithServerHeader()")
w.Header().Set("Server", "HelloServer v0.0.1")
h(w, r)
}
}
func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println("--->WithAuthCookie()")
cookie := &http.Cookie{Name: "Auth", Value: "Pass", Path: "/"}
http.SetCookie(w, cookie)
h(w, r)
}
}
func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println("--->WithBasicAuth()")
cookie, err := r.Cookie("Auth")
if err != nil || cookie.Value != "Pass" {
w.WriteHeader(http.StatusForbidden)
return
}
h(w, r)
}
}
func WithDebugLog(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println("--->WithDebugLog")
log.Println(r.Form)
log.Println("path", r.URL.Path)
log.Println("scheme", r.URL.Scheme)
log.Println(r.Form["url_long"])
for k, v := range r.Form {
log.Println("key:", k)
log.Println("val:", strings.Join(v, ""))
}
h(w, r)
}
}
func TestPipeLine(t *testing.T){
http.HandleFunc("v4/hello", Handler(hello, WithServerHeader, WithBasicAuth, WithDebugLog))
}
Channel转发函数
package main_test
import "testing"
// 会把一个整型数组放到一个Channel中,并返回这个Channel
func echo(nums []int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
// 平方
func sq(in <- chan int) <- chan int{
out := make(chan int)
go func(){
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
// 过滤奇数函数
func odd(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
if n%2 != 0 {
out <- n
}
}
close(out)
}()
return out
}
// 求和函数
func sum(in <-chan int) <-chan int {
out := make(chan int)
go func() {
var sum = 0
for n := range in {
sum += n
}
out <- sum
close(out)
}()
return out
}
func TestChannel(t *testing.T){
var nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
for n := range sum(odd(sq(echo(nums)))){
t.Log(n)
}
}
type EchoFunc func([]int) (<-chan int)
type PipeFunc func(<- chan int)(<-chan int)
func pipeline(nums []int, echo EchoFunc, pipelines ...PipeFunc) <- chan int {
ch := echo(nums)
for i:= range pipelines{
ch = pipelines[i](ch)
}
return ch
}
func TestChannel2(t *testing.T){
var nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
for n := range pipeline(nums, echo, sq, odd, sum){
t.Log(n)
}
}