Go 中的 Web 开发:中间件、模板、数据库及其他

Q shen 2023-06-05 17:05:46

“我的Go+语言初体验” | 征文活动进行中......

net/http包以及如何将其用于生产就绪的 Web 应用程序进行了广泛的讨论。我们主要关注路由方面以及该
http.ServeMux类型的其他怪癖和特性。

本文将ServeMux通过演示如何使用默认路由器实现中间件功能并介绍在使用 Go 开发 Web 服务时肯定会派上用场的其他标准库包来结束讨论。

Go 中的中间件

设置需要为许多或所有 HTTP 请求运行的共享功能的做法称为中间件。一些操作,如身份验证、日志记录和 cookie 验证,通常作为中间件功能实现,它们在常规路由处理程序之前或之后独立地处理请求。

要在 Go 中实现中间件,你需要确保你有一个满足http.Handler接口的类型。通常,这意味着您需要将带有签名的方法附加
ServeHTTP(http.ResponseWriter, *http.Request)到类型。使用此方法时,任何类型都将满足该http.Handler接口。

这是一个简单的例子:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>

<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">helloHandler</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">h</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">h</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>

    <span style="color:var(--syntax-text-color)">helloJohn</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloJohn</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

发送到/john路由的任何请求都将直接传递给该
helloHandler.ServeHTTP方法。您可以通过启动服务器并前往http://localhost:8080/john 来观察实际情况。

ServeHTTP每次要实现一个方法时都必须将方法添加到自定义类型http.Handler会非常乏味,因此该net/http包提供了该http.HandlerFunc类型,它允许将普通函数用作 HTTP 处理程序。

您需要做的就是确保您的函数具有以下签名
func(http.ResponseWriter, *http.Request):然后,将其转换为
http.HandlerFunc类型。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello John"</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
    <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">))</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

您甚至可以将上面函数mux.Handle中的行替换为,并将该函数直接传递给它。我们在上一篇文章中专门使用了这种模式。mainmux.HandleFunc

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
    <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandleFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloJohnHandler</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

此时,名称被硬编码到字符串中,这与之前我们能够在main调用处理程序之前在函数中设置名称不同。要消除此限制,我们可以将处理程序逻辑放入闭包中,如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-string-color)">"net/http"</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">))</span>
    <span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
    <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">))</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

函数helloHandler本身不满足http.Handler接口,但它创建并返回一个满足接口的匿名函数。此函数关闭name参数,这意味着它可以在调用时访问它。此时,该helloHandler函数可以根据需要重复用于许多不同的名称。

那么,这一切与中间件有什么关系呢?好吧,创建中间件函数的方法与我们在上面看到的相同。我们可以将链中的下一个处理程序作为参数传递,而不是将字符串传递给闭包(如示例中所示)。

这是完整的模式:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">middleware</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">next</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-comment-color)">// Middleware logic goes here...</span>
    <span style="color:var(--syntax-text-color)">next</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-text-color)">)</span>
  <span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

上面的函数middleware接受一个处理程序并返回一个处理程序。请注意我们如何能够通过将匿名函数http.Handler转换为类型来满足接口的要求http.HandlerFunc。在匿名函数的末尾,next通过调用
ServeHTTP()方法将控制权转移到处理程序。如果您需要在处理程序之间传递值,例如经过身份验证的用户的 ID,您可以使用http.Request.Context()Go 1.7 中引入的方法。

让我们编写一个简单演示此模式的中间件函数。requestTime此函数添加一个调用到请求对象的属性,随后用于helloHandler显示请求的时间戳。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"context"</span>
    <span style="color:var(--syntax-string-color)">"net/http"</span>
    <span style="color:var(--syntax-string-color)">"time"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">next</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">ctx</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Context</span><span style="color:var(--syntax-text-color)">()</span>
        <span style="color:var(--syntax-text-color)">ctx</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">context</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">WithValue</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ctx</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"requestTime"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Now</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Format</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">RFC3339</span><span style="color:var(--syntax-text-color)">))</span>
        <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">WithContext</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ctx</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">next</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ServeHTTP</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handler</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandlerFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">"<h1>Hello "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</h1>"</span>

        <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">requestTime</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">r</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Context</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Value</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"requestTime"</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-text-color)">requestTime</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">str</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ok</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-text-color)">ok</span> <span style="color:var(--syntax-text-color)">{</span>
                <span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">responseText</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)"><small>Generated at: "</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">str</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-string-color)">"</small>"</span>
            <span style="color:var(--syntax-text-color)">}</span>
        <span style="color:var(--syntax-text-color)">}</span>
        <span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Write</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">responseText</span><span style="color:var(--syntax-text-color)">))</span>
    <span style="color:var(--syntax-text-color)">})</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
    <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/john"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">requestTime</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">helloHandler</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"John"</span><span style="color:var(--syntax-text-color)">)))</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

运行中的中间件的屏幕截图

由于我们的中间件函数接受并返回一个http.Handler类型,因此可以
创建一个无限的中间件函数链,这些中间件函数相互嵌套

例如,

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">mux</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">NewServeMux</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">mux</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Handle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">middleware1</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">middleware2</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">appHandler</span><span style="color:var(--syntax-text-color)">)))</span>
</code></span></span>

 

您可以使用像Alice这样的库将
上述结构转换为更具可读性的形式,例如:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">alice</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">New</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">middleware1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">middleware2</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Then</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">appHandler</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

 

模板化

尽管模板的使用随着单页应用程序的出现而减少,但它仍然是完整 Web 开发解决方案的一个重要方面。

Go 为您的所有模板需求提供了两个包:text/templatehtml/template. 两者有相同的接口,但后者会在幕后做一些编码以防止代码注入攻击。

虽然 Go 模板不是最有表现力的,但它们可以很好地完成工作,并且可以用于生产应用程序。事实上,流行的静态站点生成器 Hugo 的模板系统就是基于它。

让我们快速了解一下该html/template包如何用于发送 HTML 输出作为对 Web 请求的响应。

创建模板

index.html在你的文件所在的目录下创建一个文件main.go,并在该文件中添加以下代码:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)"><ul></span>
  {{ range .TodoItems }}
  <span style="color:var(--syntax-error-color)"><li></span>{{ . }}<span style="color:var(--syntax-error-color)"></li></span>
  {{ end }}
<span style="color:var(--syntax-error-color)"></ul></span>
</code></span></span>

 

接下来,将以下代码添加到您的main.go文件中:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"html/template"</span>
    <span style="color:var(--syntax-string-color)">"log"</span>
    <span style="color:var(--syntax-string-color)">"os"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">template</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ParseFiles</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"index.html"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">todos</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"Watch TV"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Do homework"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Play games"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Read"</span><span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Execute</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">os</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Stdout</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">todos</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

如果你用go run main.go. 您应该看到以下输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-error-color)"><ul></span>
  <span style="color:var(--syntax-error-color)"><li></span>Watch TV<span style="color:var(--syntax-error-color)"></li></span>
  <span style="color:var(--syntax-error-color)"><li></span>Do homework<span style="color:var(--syntax-error-color)"></li></span>
  <span style="color:var(--syntax-error-color)"><li></span>Play games<span style="color:var(--syntax-error-color)"></li></span>
  <span style="color:var(--syntax-error-color)"><li></span>Read<span style="color:var(--syntax-error-color)"></li></span>
<span style="color:var(--syntax-error-color)"></ul></span>
</code></span></span>

 

恭喜!您刚刚创建了第一个 Go 模板。以下是我们在模板文件中使用的语法的简短说明:

  • Go 使用双大括号({{}})来分隔模板中的数据评估和控制结构(称为操作)。
  • 操作range是我们如何能够迭代数据结构,例如切片。
  • .表示当前上下文。在range动作中,当前上下文是 的切片todos。在块内部,{{ . }}指的是切片中的每个元素。

main.go文件中,该template.ParseFiles方法用于从一个或多个文件创建新模板。该模板随后使用该template.Execute方法执行;它需要一个io.Writer和数据,这些数据将应用于模板。

在上面的例子中,模板被执行到标准输出,但我们可以将它执行到任何目的地,只要它满足接口io.Writer。例如,如果您想要将输出作为 Web 请求的一部分返回,您需要做的就是将模板执行到界面ResponseWriter,如下所示。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"html/template"</span>
    <span style="color:var(--syntax-string-color)">"log"</span>
    <span style="color:var(--syntax-string-color)">"net/http"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">template</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ParseFiles</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"index.html"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">todos</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">{</span><span style="color:var(--syntax-string-color)">"Watch TV"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Do homework"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Play games"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"Read"</span><span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">HandleFunc</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"/todos"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">func</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ResponseWriter</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">r</span> <span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Request</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Header</span><span style="color:var(--syntax-text-color)">()</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Set</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Content-Type"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"text/html"</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">t</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Execute</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">todos</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">w</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(),</span> <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">StatusInternalServerError</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">})</span>
    <span style="color:var(--syntax-text-color)">http</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">ListenAndServe</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">":8080"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">nil</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

在 Chrome 中呈现的 HTML 输出图像

本节只是为了快速介绍 Go 的模板包。

如果您不喜欢 Go 的模板制作方式,可以使用替代方案,例如Plush 库

使用 JSON

如果您需要使用 JSON 对象,您会很高兴听到 Go 的标准库包含通过包解析和编码 JSON 所需的一切encoding/json

默认类型

在 Go 中编码或解码 JSON 对象时,使用以下类型:

  • bool对于 JSON 布尔值,
  • float64对于 JSON 数字,
  • string对于 JSON 字符串,
  • nil对于 JSON 空值,
  • map[string]interface{}对于 JSON 对象,以及
  • []interface{}对于 JSON 数组。

编码

要将数据结构编码为 JSON,json.Marshal可使用该函数。这是一个例子:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"encoding/json"</span>
    <span style="color:var(--syntax-string-color)">"fmt"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">Person</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">FirstName</span> <span style="color:var(--syntax-declaration-color)">string</span>
    <span style="color:var(--syntax-text-color)">LastName</span>  <span style="color:var(--syntax-declaration-color)">string</span>
    <span style="color:var(--syntax-text-color)">Age</span>       <span style="color:var(--syntax-declaration-color)">int</span>
    <span style="color:var(--syntax-text-color)">email</span>     <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">p</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">Person</span><span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">FirstName</span><span style="color:var(--syntax-error-color)">:</span> <span style="color:var(--syntax-string-color)">"Abraham"</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">LastName</span><span style="color:var(--syntax-error-color)">:</span>  <span style="color:var(--syntax-string-color)">"Freeman"</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">Age</span><span style="color:var(--syntax-error-color)">:</span>       <span style="color:var(--syntax-literal-color)">100</span><span style="color:var(--syntax-text-color)">,</span>
        <span style="color:var(--syntax-text-color)">email</span><span style="color:var(--syntax-error-color)">:</span>     <span style="color:var(--syntax-string-color)">"abraham.freeman@hey.com"</span><span style="color:var(--syntax-text-color)">,</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Marshal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-declaration-color)">return</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

在上面的程序中,我们有一个Person包含四个不同字段的结构。在该main函数中,创建了一个实例Person,并初始化了所有字段。json.Marshal然后使用该方法将p结构转换为 JSON。此方法返回字节片段或错误,我们必须在访问 JSON 数据之前处理这些错误。

要在 Go 中将字节切片转换为字符串,我们需要执行类型转换,如上所示。运行该程序将产生以下
输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{"FirstName":"Abraham","LastName":"Freeman","Age":100}
</code></span></span>

 

如您所见,我们得到了一个有效的 JSON 对象,可以以我们想要的任何方式使用。请注意,该email字段被排除在结果之外。这是因为它不是Person由于以小写字母开头而从对象中导出的。

默认情况下,Go 在结构中使用相同的属性名称作为结果 JSON 对象中的字段名称。然而,这可以通过使用 struct 字段标签来改变。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-text-color)">Person</span> <span style="color:var(--syntax-declaration-color)">struct</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">FirstName</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"first_name"`</span>
    <span style="color:var(--syntax-text-color)">LastName</span>  <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"last_name"`</span>
    <span style="color:var(--syntax-text-color)">Age</span>       <span style="color:var(--syntax-declaration-color)">int</span>    <span style="color:var(--syntax-string-color)">`json:"age"`</span>
    <span style="color:var(--syntax-text-color)">email</span>     <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-string-color)">`json:"email"`</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

上面的struct 字段标签指定JSON 编码器应该将FirstNamestruct 中的属性映射到first_nameJSON 对象中的字段等等。上一个示例中的此更改会产生以下输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{"first_name":"Abraham","last_name":"Freeman","age":100}
</code></span></span>

 

解码

json.Unmarshal函数用于将 JSON 对象解码为 Go 结构。它具有以下签名:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">Unmarshal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">data</span> <span style="color:var(--syntax-text-color)">[]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">v</span> <span style="color:var(--syntax-declaration-color)">interface</span><span style="color:var(--syntax-text-color)">{})</span> <span style="color:var(--syntax-declaration-color)">error</span>
</code></span></span>

 

它接受 JSON 数据的字节切片和存储解码数据的位置。如果解码成功,返回的错误将是nil

假设我们有以下 JSON 对象,

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">json</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">"{"</span><span style="color:var(--syntax-text-color)">first_name</span><span style="color:var(--syntax-string-color)">":"</span><span style="color:var(--syntax-text-color)">John</span><span style="color:var(--syntax-string-color)">","</span><span style="color:var(--syntax-text-color)">last_name</span><span style="color:var(--syntax-string-color)">":"</span><span style="color:var(--syntax-text-color)">Smith</span><span style="color:var(--syntax-string-color)">","</span><span style="color:var(--syntax-text-color)">age</span><span style="color:var(--syntax-string-color)">":35, "</span><span style="color:var(--syntax-text-color)">place_of_birth</span><span style="color:var(--syntax-string-color)">": "</span><span style="color:var(--syntax-text-color)">London</span><span style="color:var(--syntax-string-color)">", gender:"</span><span style="color:var(--syntax-text-color)">male</span><span style="color:var(--syntax-string-color)">"}"</span>
</code></span></span>

 

我们可以将其解码为结构的一个实例Person,如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-string-color)">`{"first_name":"John","last_name":"Smith","age":35, "place_of_birth": "London", "gender":"male", "email": "john.smith@hmail.com"}`</span>
    <span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">p</span> <span style="color:var(--syntax-text-color)">Person</span>
    <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">json</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Unmarshal</span><span style="color:var(--syntax-text-color)">([]</span><span style="color:var(--syntax-declaration-color)">byte</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-declaration-color)">return</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Printf</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"%+v</span><span style="color:var(--syntax-literal-color)">\n</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

你会得到以下输出:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>{FirstName:John LastName:Smith Age:35 email:}
</code></span></span>

 

Unmarshal仅解码在目标类型中找到的字段。在这种情况下,place_of_birthgender被忽略,因为它们不映射到Person. 可以利用此行为从大型 JSON 对象中仅选择几个特定字段。和以前一样,目标结构中未导出的字段不受影响,即使它们在 JSON 对象中有相应的字段也是如此。这就是为什么email即使它存在于 JSON 对象中,输出中仍然是一个空字符串。

数据库

database/sql包提供了一个围绕 SQL(或类似 SQL)数据库的通用接口。它必须与数据库驱动程序结合使用,例如此处列出的驱动程序。导入数据库驱动时,需要在其前面加上下划线_作为初始化

例如,下面是如何使用MySQL 驱动程序包database/sql

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"database/sql"</span>
    <span style="color:var(--syntax-text-color)">_</span> <span style="color:var(--syntax-string-color)">"github.com/go-sql-driver/mysql"</span>
<span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

 

在引擎盖下,驱动程序将自己注册为对包可用database/sql,但它不会直接在我们的代码中使用。这有助于我们减少对特定驱动程序的依赖,以便可以轻松地将其换成另一个驱动程序。

打开数据库连接

要访问数据库,您需要创建一个sql.DB对象,如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">sql</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"mysql"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"user:password@tcp(127.0.0.1:3306)/hello"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

sql.Open方法准备数据库抽象供以后使用。它不建立与数据库的连接或验证连接参数。如果要确保数据库立即可用和可访问,请使用以下db.Ping()方法:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Ping</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

关闭数据库连接

要关闭数据库连接,您可以使用db.Close(). 通常,您希望defer关闭数据库直到打开数据库连接的函数结束,通常是函数main

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">sql</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Open</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"mysql"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">"user:password@tcp(127.0.0.1:3306)/hello"</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-declaration-color)">defer</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Close</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

sql.DB对象被设计为长期存在的,因此您不应频繁打开和关闭它。如果这样做,您可能会遇到问题,例如连接重用和共享不佳、可用网络资源耗尽或偶发故障。最好传递该sql.DB方法或使其全局可用,并且仅在程序完成访问该数据存储时才关闭它。

从数据库中获取数据

查询表可以分三步完成。首先,打电话db.Query()。然后,遍历行。最后,使用rows.Scan()将每一行提取到变量中。这是一个例子:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)">id</span> <span style="color:var(--syntax-declaration-color)">int</span>
    <span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Query</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"select id, name from users where id = ?"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">defer</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Close</span><span style="color:var(--syntax-text-color)">()</span>

<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Next</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Scan</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>

    <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">rows</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Err</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

 

如果查询返回单行,您可以使用该db.QueryRow方法代替db.Query并避免前面代码片段中的一些冗长的样板代码:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">var</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-text-color)">id</span> <span style="color:var(--syntax-declaration-color)">int</span>
    <span style="color:var(--syntax-text-color)">name</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">db</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">QueryRow</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"select id, name from users where id = ?"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Scan</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-error-color)">&</span><span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">err</span> <span style="color:var(--syntax-error-color)">!=</span> <span style="color:var(--syntax-declaration-color)">nil</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">log</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Fatal</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">err</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">id</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>

 

NoSQL 数据库

Go 还对 NoSQL 数据库有很好的支持,例如 Redis、MongoDB、Cassandra 等,但它没有提供与它们一起工作的标准接口。您必须完全依赖特定数据库的驱动程序包。下面列出了一些示例。

总结

在本文中,我们讨论了
使用 Go 构建 Web 应用程序的一些重要方面。您现在应该能够理解为什么许多 Go 程序员对标准库发誓了。它非常全面,提供了生产就绪服务所需的大部分工具。

如果您喜欢这篇文章,请点赞、评论和分享。

...全文
319 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

1,071

社区成员

发帖
与我相关
我的任务
社区描述
Go+ 官方开发者社区。我们希望向广大的开发者和数据科学家介绍 Go+ 的定位和意义,并邀请更多开发者一起贡献代码、共建 Go+ 生态。 Go+ 官网:https://goplus.org/
其他 企业社区
社区管理员
  • Go+
  • 杨东杰
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

本社区为 Go+ 官方开发者社区。我们希望向广大的开发者和数据科学家介绍 Go+ 的定位和意义,并邀请更多开发者一起贡献代码、共建 Go+ 生态。

Go+ 官网:https://goplus.org/
GitHub地址:https://github.com/goplus/gop

试试用AI创作助手写篇文章吧