最近打算写一个golang版本的requests库用,遇到一个问题是如何模拟python函数的关键字参数。

举个栗子,我需要实现一个设置timeout和headers的功能,requests可以这样设置

1
2

requests.get(url, headers={"content-type": "application/json"}, timeout=10)

那用go如何实现呢?其实只需要写两个函数设置headers和timeout,然后作为可变参数传到发送请求的函数里就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


func (r *Request) setHeaders(headers map[string]string) error {
r.Args["headers"] = headers
return nil
}


func Headers(headers map[string]string) func(*Request) error {
return func(r *Request) error {
return r.setHeaders(headers)
}
}

func (r *Request) MakeRequest(method string, uri string, options ...func(*Request) error) (*Response, error) {
}

附完整代码实现:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

package main

import "fmt"

import "time"
import "net/http"
import "io/ioutil"

type M map[string]interface{}

type Request struct {
Url string
Args M
}

type Response struct {
Content string
}

func (r *Request) setHeaders(headers map[string]string) error {
r.Args["headers"] = headers
return nil
}

func Headers(headers map[string]string) func(*Request) error {
return func(r *Request) error {
return r.setHeaders(headers)
}
}

func (r *Request) setTimeout(timeout int) error {
r.Args["timeout"] = int(timeout)
return nil
}

func Timeout(timeout int) func(*Request) error {
return func(r *Request) error {
return r.setTimeout(timeout)
}
}

func (r *Request) MakeRequest(method string, uri string, options ...func(*Request) error) (*Response, error) {

req, err := http.NewRequest(method, uri, nil)

for _, option := range options {
err := option(r)
if err != nil {
panic(err)
}
}

transport := &http.Transport{}
client := &http.Client{
Transport: transport,
}

timeoutSeconds := r.Args["timeout"].(int)
timeout := time.Duration(0) * time.Second
if timeoutSeconds > 0 {
timeout = time.Duration(timeoutSeconds) * time.Second
}
client.Timeout = timeout

resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
response := &Response{}
if err != nil {
panic(err)
} else {
response.Content = string(body)
}
return response, nil
}

func main() {
kwargs := M{}
headers := map[string]string{
"content-Type": "application/json",
"user-agent": "Golang requests",
}

req := &Request{Args: kwargs}
resp, _ := req.MakeRequest("GET", "http://www.example.com", Timeout(10), Headers(headers))
fmt.Println(resp.Content)
resp, _ = req.MakeRequest("GET", "http://www.example.com", Timeout(1), Headers(headers))
fmt.Println(resp.Content)
}

参考: