274 lines
17 KiB
Plaintext
Generated
274 lines
17 KiB
Plaintext
Generated
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Go by Example: Errors</title>
|
|
<link rel=stylesheet href="site.css">
|
|
</head>
|
|
<script>
|
|
window.onkeydown = (e) => {
|
|
if (e.ctrlKey || e.altKey || e.shiftKey) {
|
|
return;
|
|
}
|
|
|
|
if (e.key == "ArrowLeft") {
|
|
window.location.href = 'range-over-iterators';
|
|
}
|
|
|
|
|
|
if (e.key == "ArrowRight") {
|
|
window.location.href = 'custom-errors';
|
|
}
|
|
|
|
}
|
|
</script>
|
|
<body>
|
|
<div class="example" id="errors">
|
|
<h2><a href="./">Go by Example</a>: Errors</h2>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>In Go it’s idiomatic to communicate errors via an
|
|
explicit, separate return value. This contrasts with
|
|
the exceptions used in languages like Java and Ruby and
|
|
the overloaded single result / error value sometimes
|
|
used in C. Go’s approach makes it easy to see which
|
|
functions return errors and to handle them using the
|
|
same language constructs employed for other,
|
|
non-error tasks.</p>
|
|
|
|
<p>See the documentation of the <a href="https://pkg.go.dev/errors">errors package</a>
|
|
and <a href="https://go.dev/blog/go1.13-errors">this blog post</a> for additional
|
|
details.</p>
|
|
|
|
</td>
|
|
<td class="code empty leading">
|
|
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
<a href="https://go.dev/play/p/j6odYuFpOeb"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="s">"errors"</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>By convention, errors are the last return value and
|
|
have type <code>error</code>, a built-in interface.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">f</span><span class="p">(</span><span class="nx">arg</span> <span class="kt">int</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">arg</span> <span class="o">==</span> <span class="mi">42</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p><code>errors.New</code> constructs a basic <code>error</code> value
|
|
with the given error message.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">"can't work with 42"</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>A <code>nil</code> value in the error position indicates that
|
|
there was no error.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">arg</span> <span class="o">+</span> <span class="mi">3</span><span class="p">,</span> <span class="kc">nil</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>A sentinel error is a predeclared variable that is used to
|
|
signify a specific error condition.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">ErrOutOfTea</span> <span class="p">=</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"no more tea available"</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">ErrPower</span> <span class="p">=</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"can't boil water"</span><span class="p">)</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">makeTea</span><span class="p">(</span><span class="nx">arg</span> <span class="kt">int</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">arg</span> <span class="o">==</span> <span class="mi">2</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">ErrOutOfTea</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">arg</span> <span class="o">==</span> <span class="mi">4</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>We can wrap errors with higher-level errors to add
|
|
context. The simplest way to do this is with the
|
|
<code>%w</code> verb in <code>fmt.Errorf</code>. Wrapped errors
|
|
create a logical chain (A wraps B, which wraps C, etc.)
|
|
that can be queried with functions like <code>errors.Is</code>
|
|
and <code>errors.As</code>.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"making tea: %w"</span><span class="p">,</span> <span class="nx">ErrPower</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">7</span><span class="p">,</span> <span class="mi">42</span><span class="p">}</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>It’s common to use an inline error check in the <code>if</code>
|
|
line.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">r</span><span class="p">,</span> <span class="nx">e</span> <span class="o">:=</span> <span class="nf">f</span><span class="p">(</span><span class="nx">i</span><span class="p">);</span> <span class="nx">e</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"f failed:"</span><span class="p">,</span> <span class="nx">e</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"f worked:"</span><span class="p">,</span> <span class="nx">r</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="k">range</span> <span class="mi">5</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">makeTea</span><span class="p">(</span><span class="nx">i</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p><code>errors.Is</code> checks that a given error (or any error in its chain)
|
|
matches a specific error value. This is especially useful with wrapped or
|
|
nested errors, allowing you to identify specific error types or sentinel
|
|
errors in a chain of errors.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">ErrOutOfTea</span><span class="p">)</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"We should buy new tea!"</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">ErrPower</span><span class="p">)</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Now it is dark."</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"unknown error: %s\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">continue</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Tea is ready!"</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="gp">$</span> go run errors.go
|
|
</span></span><span class="line"><span class="cl"><span class="go">f worked: 10
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">f failed: can't work with 42
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">Tea is ready!
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">Tea is ready!
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">We should buy new tea!
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">Tea is ready!
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">Now it is dark.</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
<p class="next">
|
|
Next example: <a href="custom-errors">Custom Errors</a>.
|
|
</p>
|
|
|
|
|
|
<p class="footer">
|
|
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a> and <a href="https://eli.thegreenplace.net">Eli Bendersky</a> | <a href="https://github.com/mmcgrana/gobyexample">source</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>
|
|
</p>
|
|
|
|
</div>
|
|
<script>
|
|
var codeLines = [];
|
|
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import (\u000A \"errors\"\u000A \"fmt\"\u000A)\u000A');codeLines.push('func f(arg int) (int, error) {\u000A if arg \u003D\u003D 42 {\u000A');codeLines.push(' return -1, errors.New(\"can\'t work with 42\")\u000A }\u000A');codeLines.push(' return arg + 3, nil\u000A}\u000A');codeLines.push('var ErrOutOfTea \u003D fmt.Errorf(\"no more tea available\")\u000Avar ErrPower \u003D fmt.Errorf(\"can\'t boil water\")\u000A');codeLines.push('func makeTea(arg int) error {\u000A if arg \u003D\u003D 2 {\u000A return ErrOutOfTea\u000A } else if arg \u003D\u003D 4 {\u000A');codeLines.push(' return fmt.Errorf(\"making tea: %w\", ErrPower)\u000A }\u000A return nil\u000A}\u000A');codeLines.push('func main() {\u000A for _, i :\u003D range []int{7, 42} {\u000A');codeLines.push(' if r, e :\u003D f(i); e !\u003D nil {\u000A fmt.Println(\"f failed:\", e)\u000A } else {\u000A fmt.Println(\"f worked:\", r)\u000A }\u000A }\u000A');codeLines.push(' for i :\u003D range 5 {\u000A if err :\u003D makeTea(i); err !\u003D nil {\u000A');codeLines.push(' if errors.Is(err, ErrOutOfTea) {\u000A fmt.Println(\"We should buy new tea!\")\u000A } else if errors.Is(err, ErrPower) {\u000A fmt.Println(\"Now it is dark.\")\u000A } else {\u000A fmt.Printf(\"unknown error: %s\\n\", err)\u000A }\u000A continue\u000A }\u000A');codeLines.push(' fmt.Println(\"Tea is ready!\")\u000A }\u000A}\u000A');codeLines.push('');
|
|
</script>
|
|
<script src="site.js" async></script>
|
|
</body>
|
|
</html>
|