mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-21 00:47:11 +08:00
Reorganization
This commit is contained in:
parent
10df7d4890
commit
89a5a20bac
16 changed files with 1182 additions and 481 deletions
BIN
.cache/plugin/social/abbb864f7d61c8efb7242d6041360832.png
Normal file
BIN
.cache/plugin/social/abbb864f7d61c8efb7242d6041360832.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
30
docs/book.md
30
docs/book.md
|
|
@ -12,7 +12,7 @@ Source code and community space of _100 Go Mistakes and How to Avoid Them_, publ
|
|||
|
||||
If you're a Go developer looking to improve your skills, this book is for you. With a focus on practical examples, _100 Go Mistakes and How to Avoid Them_ covers a wide range of topics from concurrency and error handling to testing and code organization. You'll learn to write more idiomatic, efficient, and maintainable code and become a proficient Go developer.
|
||||
|
||||
### Quotes
|
||||
## Quotes
|
||||
|
||||
> This is an exceptional book. Usually, if a book contains either high-quality explanations or is written succinctly, I consider myself lucky to have found it. This one combines these two characteristics, which is super rare. It's another Go book for me and I still had quite a lot of "a-ha!" moments while reading it, and all of that without the unnecessary fluff, just straight to the point.
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ If you're a Go developer looking to improve your skills, this book is for you. W
|
|||
|
||||
– _Anupam Sengupta_
|
||||
|
||||
### Where to Buy?
|
||||
## Where to Buy?
|
||||
|
||||
* _100 Go Mistakes and How to Avoid Them_ (🇬🇧 edition: paper, digital, or audiobook)
|
||||
* [Manning](https://www.manning.com/books/100-go-mistakes-and-how-to-avoid-them)
|
||||
|
|
@ -39,29 +39,3 @@ If you're a Go developer looking to improve your skills, this book is for you. W
|
|||
## About the Author
|
||||
|
||||
Teiva Harsanyi is a senior software engineer at Google. He has worked in various domains, including insurance, transportation, and safety-critical industries like air traffic management. He is passionate about Go and how to design and implement reliable systems.
|
||||
|
||||
## External Resources
|
||||
|
||||
### English
|
||||
|
||||
* Book Review: 100 Go Mistakes and How to Avoid Them: [Post](https://boldlygo.tech/posts/2023-08-09-review-100-go-mistakes/), [YouTube](https://www.youtube.com/watch?v=tcRYU9g5wtw)
|
||||
* How to make mistakes in Go - Go Time #190: [Episode](https://changelog.com/gotime/190), [Spotify](https://open.spotify.com/episode/0K1DImrxHCy6E7zVY4AxMZ?si=akroInsPQ1mM5B5V2tHLUw&dl_branch=1)
|
||||
* [8LU - 100% Test Coverage](https://youtu.be/V3FBDav6wgQ?t=1210)
|
||||
* [Some Tips I learned from 100 Mistakes in Go](https://raygervais.dev/articles/2023/04/100_mistakes_in_go/)
|
||||
* [What can be summarized from 100 Go Mistakes?](https://www.sobyte.net/post/2023-05/summarized-from-100-go-mistakes/)
|
||||
|
||||
### Chinese
|
||||
|
||||
* [深度阅读之《100 Go Mistakes and How to Avoid Them](https://qcrao.com/post/100-go-mistakes-reading-notes/)
|
||||
* [100 Go Mistakes 随记](https://zhuanlan.zhihu.com/p/592602656)
|
||||
* [我为什么放弃Go语言?](https://juejin.cn/post/7241452578125824061)
|
||||
|
||||
### Japanese
|
||||
|
||||
* [最近読んだGo言語の本の紹介:100 Go Mistakes and How to Avoid Them](https://qiita.com/kentaro_suzuki/items/c9c31dc81217f237433c)
|
||||
* [『100 Go Mistakes and How to Avoid Them』を読む](https://zenn.dev/yukibobier/books/066f07c8a59fa0)
|
||||
* [100 Go Mistakes 随记 - 01 Code and project organization](https://zhuanlan.zhihu.com/p/592602656)
|
||||
|
||||
### Portuguese
|
||||
|
||||
* [Um ÓTIMO livro para programadores Go](https://www.youtube.com/watch?v=34XShL_jWD4)
|
||||
|
|
|
|||
25
docs/external.md
Normal file
25
docs/external.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# External Resources
|
||||
|
||||
## English
|
||||
|
||||
* Book Review: 100 Go Mistakes and How to Avoid Them: [Post](https://boldlygo.tech/posts/2023-08-09-review-100-go-mistakes/), [YouTube](https://www.youtube.com/watch?v=tcRYU9g5wtw)
|
||||
* How to make mistakes in Go - Go Time #190: [Episode](https://changelog.com/gotime/190), [Spotify](https://open.spotify.com/episode/0K1DImrxHCy6E7zVY4AxMZ?si=akroInsPQ1mM5B5V2tHLUw&dl_branch=1)
|
||||
* [8LU - 100% Test Coverage](https://youtu.be/V3FBDav6wgQ?t=1210)
|
||||
* [Some Tips I learned from 100 Mistakes in Go](https://raygervais.dev/articles/2023/04/100_mistakes_in_go/)
|
||||
* [What can be summarized from 100 Go Mistakes?](https://www.sobyte.net/post/2023-05/summarized-from-100-go-mistakes/)
|
||||
|
||||
## Chinese
|
||||
|
||||
* [深度阅读之《100 Go Mistakes and How to Avoid Them](https://qcrao.com/post/100-go-mistakes-reading-notes/)
|
||||
* [100 Go Mistakes 随记](https://zhuanlan.zhihu.com/p/592602656)
|
||||
* [我为什么放弃Go语言?](https://juejin.cn/post/7241452578125824061)
|
||||
|
||||
## Japanese
|
||||
|
||||
* [最近読んだGo言語の本の紹介:100 Go Mistakes and How to Avoid Them](https://qiita.com/kentaro_suzuki/items/c9c31dc81217f237433c)
|
||||
* [『100 Go Mistakes and How to Avoid Them』を読む](https://zenn.dev/yukibobier/books/066f07c8a59fa0)
|
||||
* [100 Go Mistakes 随记 - 01 Code and project organization](https://zhuanlan.zhihu.com/p/592602656)
|
||||
|
||||
## Portuguese
|
||||
|
||||
* [Um ÓTIMO livro para programadores Go](https://www.youtube.com/watch?v=34XShL_jWD4)
|
||||
|
|
@ -157,7 +157,7 @@ When creating a struct, Go offers the option to embed types. But this can someti
|
|||
|
||||
In Go, a struct field is called embedded if it’s declared without a name. For example,
|
||||
|
||||
```cgo
|
||||
```go
|
||||
type Foo struct {
|
||||
Bar // Embedded field
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,4 +44,13 @@ nav:
|
|||
- jobs.md
|
||||
- Chinese (Simplified):
|
||||
- zh/index.md
|
||||
- external.md
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
line_spans: __span
|
||||
pygments_lang_class: true
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.snippets
|
||||
- pymdownx.superfences
|
||||
copyright: Copyright © 2022 - 2023 Teiva Harsanyi
|
||||
|
|
|
|||
|
|
@ -404,6 +404,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
BIN
site/assets/images/social/external.png
Normal file
BIN
site/assets/images/social/external.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -358,8 +358,7 @@
|
|||
Book Description
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Book Description">
|
||||
<ul class="md-nav__list">
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#quotes" class="md-nav__link">
|
||||
|
|
@ -373,11 +372,6 @@
|
|||
Where to Buy?
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
|
|
@ -385,47 +379,6 @@
|
|||
About the Author
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#external-resources" class="md-nav__link">
|
||||
External Resources
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="External Resources">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#english" class="md-nav__link">
|
||||
English
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#chinese" class="md-nav__link">
|
||||
Chinese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#japanese" class="md-nav__link">
|
||||
Japanese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#portuguese" class="md-nav__link">
|
||||
Portuguese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
|
@ -554,6 +507,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -585,8 +557,7 @@
|
|||
Book Description
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="Book Description">
|
||||
<ul class="md-nav__list">
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#quotes" class="md-nav__link">
|
||||
|
|
@ -600,11 +571,6 @@
|
|||
Where to Buy?
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
|
|
@ -612,47 +578,6 @@
|
|||
About the Author
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#external-resources" class="md-nav__link">
|
||||
External Resources
|
||||
</a>
|
||||
|
||||
<nav class="md-nav" aria-label="External Resources">
|
||||
<ul class="md-nav__list">
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#english" class="md-nav__link">
|
||||
English
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#chinese" class="md-nav__link">
|
||||
Chinese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#japanese" class="md-nav__link">
|
||||
Japanese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#portuguese" class="md-nav__link">
|
||||
Portuguese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
|
@ -678,7 +603,7 @@
|
|||
<p><img alt="" src="../img/cover.png" /></p>
|
||||
<h2 id="book-description">Book Description</h2>
|
||||
<p>If you're a Go developer looking to improve your skills, this book is for you. With a focus on practical examples, <em>100 Go Mistakes and How to Avoid Them</em> covers a wide range of topics from concurrency and error handling to testing and code organization. You'll learn to write more idiomatic, efficient, and maintainable code and become a proficient Go developer.</p>
|
||||
<h3 id="quotes">Quotes</h3>
|
||||
<h2 id="quotes">Quotes</h2>
|
||||
<blockquote>
|
||||
<p>This is an exceptional book. Usually, if a book contains either high-quality explanations or is written succinctly, I consider myself lucky to have found it. This one combines these two characteristics, which is super rare. It's another Go book for me and I still had quite a lot of "a-ha!" moments while reading it, and all of that without the unnecessary fluff, just straight to the point.</p>
|
||||
</blockquote>
|
||||
|
|
@ -691,7 +616,7 @@
|
|||
<p>Not having this will be the 101st mistake a Go programmer could make.</p>
|
||||
</blockquote>
|
||||
<p>– <em>Anupam Sengupta</em></p>
|
||||
<h3 id="where-to-buy">Where to Buy?</h3>
|
||||
<h2 id="where-to-buy">Where to Buy?</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<p><em>100 Go Mistakes and How to Avoid Them</em> (🇬🇧 edition: paper, digital, or audiobook)</p>
|
||||
|
|
@ -710,31 +635,6 @@
|
|||
</ul>
|
||||
<h2 id="about-the-author">About the Author</h2>
|
||||
<p>Teiva Harsanyi is a senior software engineer at Google. He has worked in various domains, including insurance, transportation, and safety-critical industries like air traffic management. He is passionate about Go and how to design and implement reliable systems.</p>
|
||||
<h2 id="external-resources">External Resources</h2>
|
||||
<h3 id="english">English</h3>
|
||||
<ul>
|
||||
<li>Book Review: 100 Go Mistakes and How to Avoid Them: <a href="https://boldlygo.tech/posts/2023-08-09-review-100-go-mistakes/">Post</a>, <a href="https://www.youtube.com/watch?v=tcRYU9g5wtw">YouTube</a></li>
|
||||
<li>How to make mistakes in Go - Go Time #190: <a href="https://changelog.com/gotime/190">Episode</a>, <a href="https://open.spotify.com/episode/0K1DImrxHCy6E7zVY4AxMZ?si=akroInsPQ1mM5B5V2tHLUw&dl_branch=1">Spotify</a></li>
|
||||
<li><a href="https://youtu.be/V3FBDav6wgQ?t=1210">8LU - 100% Test Coverage</a></li>
|
||||
<li><a href="https://raygervais.dev/articles/2023/04/100_mistakes_in_go/">Some Tips I learned from 100 Mistakes in Go</a></li>
|
||||
<li><a href="https://www.sobyte.net/post/2023-05/summarized-from-100-go-mistakes/">What can be summarized from 100 Go Mistakes?</a></li>
|
||||
</ul>
|
||||
<h3 id="chinese">Chinese</h3>
|
||||
<ul>
|
||||
<li><a href="https://qcrao.com/post/100-go-mistakes-reading-notes/">深度阅读之《100 Go Mistakes and How to Avoid Them</a></li>
|
||||
<li><a href="https://zhuanlan.zhihu.com/p/592602656">100 Go Mistakes 随记</a></li>
|
||||
<li><a href="https://juejin.cn/post/7241452578125824061">我为什么放弃Go语言?</a></li>
|
||||
</ul>
|
||||
<h3 id="japanese">Japanese</h3>
|
||||
<ul>
|
||||
<li><a href="https://qiita.com/kentaro_suzuki/items/c9c31dc81217f237433c">最近読んだGo言語の本の紹介:100 Go Mistakes and How to Avoid Them</a></li>
|
||||
<li><a href="https://zenn.dev/yukibobier/books/066f07c8a59fa0">『100 Go Mistakes and How to Avoid Them』を読む</a></li>
|
||||
<li><a href="https://zhuanlan.zhihu.com/p/592602656">100 Go Mistakes 随记 - 01 Code and project organization</a></li>
|
||||
</ul>
|
||||
<h3 id="portuguese">Portuguese</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.youtube.com/watch?v=34XShL_jWD4">Um ÓTIMO livro para programadores Go</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -564,6 +564,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
691
site/external/index.html
vendored
Normal file
691
site/external/index.html
vendored
Normal file
|
|
@ -0,0 +1,691 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
|
||||
|
||||
<link rel="canonical" href="https://100go.co/external/">
|
||||
|
||||
|
||||
<link rel="prev" href="../zh/">
|
||||
|
||||
|
||||
|
||||
<link rel="icon" href="../Go-Logo_Fuchsia.svg">
|
||||
<meta name="generator" content="mkdocs-1.5.2, mkdocs-material-9.3.1">
|
||||
|
||||
|
||||
<title>100 Go Mistakes</title>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/main.046329b4.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/palette.85d0ee34.min.css">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||||
|
||||
|
||||
|
||||
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<script id="__analytics">function __md_analytics(){function n(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],n("js",new Date),n("config","G-HMY1HYDM93"),document.addEventListener("DOMContentLoaded",function(){document.forms.search&&document.forms.search.query.addEventListener("blur",function(){this.value&&n("event","search",{search_term:this.value})}),document$.subscribe(function(){var a=document.forms.feedback;if(void 0!==a)for(var e of a.querySelectorAll("[type=submit]"))e.addEventListener("click",function(e){e.preventDefault();var t=document.location.pathname,e=this.getAttribute("data-md-value");n("event","feedback",{page:t,data:e}),a.firstElementChild.disabled=!0;e=a.querySelector(".md-feedback__note [data-md-value='"+e+"']");e&&(e.hidden=!1)}),a.hidden=!1}),location$.subscribe(function(e){n("config","G-HMY1HYDM93",{page_path:e.pathname})})});var e=document.createElement("script");e.async=!0,e.src="https://www.googletagmanager.com/gtag/js?id=G-HMY1HYDM93",document.getElementById("__analytics").insertAdjacentElement("afterEnd",e)}</script>
|
||||
|
||||
<script>"undefined"!=typeof __md_analytics&&__md_analytics()</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<meta property="og:type" content="website" >
|
||||
|
||||
<meta property="og:title" content="External Resources - 100 Go Mistakes" >
|
||||
|
||||
<meta property="og:description" content="None" >
|
||||
|
||||
<meta property="og:image" content="https://100go.co/assets/images/social/external.png" >
|
||||
|
||||
<meta property="og:image:type" content="image/png" >
|
||||
|
||||
<meta property="og:image:width" content="1200" >
|
||||
|
||||
<meta property="og:image:height" content="630" >
|
||||
|
||||
<meta property="og:url" content="https://100go.co/external/" >
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" >
|
||||
|
||||
<meta name="twitter:title" content="External Resources - 100 Go Mistakes" >
|
||||
|
||||
<meta name="twitter:description" content="None" >
|
||||
|
||||
<meta name="twitter:image" content="https://100go.co/assets/images/social/external.png" >
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="indigo">
|
||||
|
||||
|
||||
|
||||
<script>var palette=__md_get("__palette");if(palette&&"object"==typeof palette.color)for(var key of Object.keys(palette.color))document.body.setAttribute("data-md-color-"+key,palette.color[key])</script>
|
||||
|
||||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||||
<label class="md-overlay" for="__drawer"></label>
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#external-resources" class="md-skip">
|
||||
Skip to content
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div data-md-component="announce">
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<header class="md-header md-header--shadow" data-md-component="header">
|
||||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||||
<a href=".." title="100 Go Mistakes" class="md-header__button md-logo" aria-label="100 Go Mistakes" data-md-component="logo">
|
||||
|
||||
<img src="../img/Go-Logo_White.svg" alt="logo">
|
||||
|
||||
</a>
|
||||
<label class="md-header__button md-icon" for="__drawer">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
|
||||
</label>
|
||||
<div class="md-header__title" data-md-component="header-title">
|
||||
<div class="md-header__ellipsis">
|
||||
<div class="md-header__topic">
|
||||
<span class="md-ellipsis">
|
||||
100 Go Mistakes
|
||||
</span>
|
||||
</div>
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
External Resources
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<form class="md-header__option" data-md-component="palette">
|
||||
|
||||
|
||||
|
||||
|
||||
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
|
||||
|
||||
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69Z"/></svg>
|
||||
</label>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="blue-grey" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_2">
|
||||
|
||||
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12c0-2.42-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69Z"/></svg>
|
||||
</label>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
<div class="md-header__option">
|
||||
<div class="md-select">
|
||||
|
||||
<button class="md-header__button md-icon" aria-label="Select language">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m12.87 15.07-2.54-2.51.03-.03A17.52 17.52 0 0 0 14.07 6H17V4h-7V2H8v2H1v2h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04M18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12m-2.62 7 1.62-4.33L19.12 17h-3.24Z"/></svg>
|
||||
</button>
|
||||
<div class="md-select__inner">
|
||||
<ul class="md-select__list">
|
||||
|
||||
<li class="md-select__item">
|
||||
<a href="/" hreflang="en" class="md-select__link">
|
||||
English
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="md-select__item">
|
||||
<a href="/zh/" hreflang="zh" class="md-select__link">
|
||||
Chinese (Simplified)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<label class="md-header__button md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
</label>
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
<form class="md-search__form" name="search">
|
||||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
||||
<label class="md-search__icon md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</label>
|
||||
<nav class="md-search__options" aria-label="Search">
|
||||
|
||||
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
</form>
|
||||
<div class="md-search__output">
|
||||
<div class="md-search__scrollwrap" data-md-scrollfix>
|
||||
<div class="md-search-result" data-md-component="search-result">
|
||||
<div class="md-search-result__meta">
|
||||
Initializing search
|
||||
</div>
|
||||
<ol class="md-search-result__list" role="presentation"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-header__source">
|
||||
<a href="https://github.com/teivah/100-go-mistakes" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitHub
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
|
||||
<div class="md-container" data-md-component="container">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<main class="md-main" data-md-component="main">
|
||||
<div class="md-main__inner md-grid">
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
||||
<label class="md-nav__title" for="__drawer">
|
||||
<a href=".." title="100 Go Mistakes" class="md-nav__button md-logo" aria-label="100 Go Mistakes" data-md-component="logo">
|
||||
|
||||
<img src="../img/Go-Logo_White.svg" alt="logo">
|
||||
|
||||
</a>
|
||||
100 Go Mistakes
|
||||
</label>
|
||||
|
||||
<div class="md-nav__source">
|
||||
<a href="https://github.com/teivah/100-go-mistakes" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitHub
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../book/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Book Presentation
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../chapter-1/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Read the First Chapter
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href=".." class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
💡 Common Go Mistakes
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../jobs/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
❤️ Go Jobs
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item md-nav__item--nested">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
|
||||
|
||||
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Chinese (Simplified)
|
||||
</span>
|
||||
|
||||
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
|
||||
<label class="md-nav__title" for="__nav_5">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
Chinese (Simplified)
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../zh/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
100个Go常见错误及如何避免
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item md-nav__item--active">
|
||||
|
||||
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
Table of contents
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#english" class="md-nav__link">
|
||||
English
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#chinese" class="md-nav__link">
|
||||
Chinese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#japanese" class="md-nav__link">
|
||||
Japanese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#portuguese" class="md-nav__link">
|
||||
Portuguese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
Table of contents
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#english" class="md-nav__link">
|
||||
English
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#chinese" class="md-nav__link">
|
||||
Chinese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#japanese" class="md-nav__link">
|
||||
Japanese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#portuguese" class="md-nav__link">
|
||||
Portuguese
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-content" data-md-component="content">
|
||||
<article class="md-content__inner md-typeset">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h1 id="external-resources">External Resources</h1>
|
||||
<h2 id="english">English</h2>
|
||||
<ul>
|
||||
<li>Book Review: 100 Go Mistakes and How to Avoid Them: <a href="https://boldlygo.tech/posts/2023-08-09-review-100-go-mistakes/">Post</a>, <a href="https://www.youtube.com/watch?v=tcRYU9g5wtw">YouTube</a></li>
|
||||
<li>How to make mistakes in Go - Go Time #190: <a href="https://changelog.com/gotime/190">Episode</a>, <a href="https://open.spotify.com/episode/0K1DImrxHCy6E7zVY4AxMZ?si=akroInsPQ1mM5B5V2tHLUw&dl_branch=1">Spotify</a></li>
|
||||
<li><a href="https://youtu.be/V3FBDav6wgQ?t=1210">8LU - 100% Test Coverage</a></li>
|
||||
<li><a href="https://raygervais.dev/articles/2023/04/100_mistakes_in_go/">Some Tips I learned from 100 Mistakes in Go</a></li>
|
||||
<li><a href="https://www.sobyte.net/post/2023-05/summarized-from-100-go-mistakes/">What can be summarized from 100 Go Mistakes?</a></li>
|
||||
</ul>
|
||||
<h2 id="chinese">Chinese</h2>
|
||||
<ul>
|
||||
<li><a href="https://qcrao.com/post/100-go-mistakes-reading-notes/">深度阅读之《100 Go Mistakes and How to Avoid Them</a></li>
|
||||
<li><a href="https://zhuanlan.zhihu.com/p/592602656">100 Go Mistakes 随记</a></li>
|
||||
<li><a href="https://juejin.cn/post/7241452578125824061">我为什么放弃Go语言?</a></li>
|
||||
</ul>
|
||||
<h2 id="japanese">Japanese</h2>
|
||||
<ul>
|
||||
<li><a href="https://qiita.com/kentaro_suzuki/items/c9c31dc81217f237433c">最近読んだGo言語の本の紹介:100 Go Mistakes and How to Avoid Them</a></li>
|
||||
<li><a href="https://zenn.dev/yukibobier/books/066f07c8a59fa0">『100 Go Mistakes and How to Avoid Them』を読む</a></li>
|
||||
<li><a href="https://zhuanlan.zhihu.com/p/592602656">100 Go Mistakes 随记 - 01 Code and project organization</a></li>
|
||||
</ul>
|
||||
<h2 id="portuguese">Portuguese</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.youtube.com/watch?v=34XShL_jWD4">Um ÓTIMO livro para programadores Go</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="md-footer">
|
||||
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
<div class="md-copyright">
|
||||
|
||||
<div class="md-copyright__highlight">
|
||||
Copyright © 2022 - 2023 Teiva Harsanyi
|
||||
</div>
|
||||
|
||||
|
||||
Made with
|
||||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||||
Material for MkDocs
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="md-social">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://twitter.com/teivah" target="_blank" rel="noopener" title="twitter.com" class="md-social__link">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<div class="md-dialog" data-md-component="dialog">
|
||||
<div class="md-dialog__inner md-typeset"></div>
|
||||
</div>
|
||||
|
||||
<script id="__config" type="application/json">{"base": "..", "features": [], "search": "../assets/javascripts/workers/search.dfff1995.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
|
||||
|
||||
|
||||
<script src="../assets/javascripts/bundle.dff1b7c8.min.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
659
site/index.html
659
site/index.html
|
|
@ -1351,6 +1351,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -2284,36 +2303,36 @@
|
|||
<ul>
|
||||
<li>When an <code>if</code> block returns, we should omit the <code>else</code> block in all cases. For example, we shouldn’t write:</li>
|
||||
</ul>
|
||||
<pre><code class="language-go">if foo() {
|
||||
// ...
|
||||
return true
|
||||
} else {
|
||||
// ...
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="k">if</span><span class="w"> </span><span class="nx">foo</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Instead, we omit the <code>else</code> block like this:</p>
|
||||
<pre><code class="language-go">if foo() {
|
||||
// ...
|
||||
return true
|
||||
}
|
||||
// ...
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="k">if</span><span class="w"> </span><span class="nx">foo</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span>
|
||||
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="p">}</span>
|
||||
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="c1">// ...</span>
|
||||
</span></code></pre></div>
|
||||
<ul>
|
||||
<li>We can also follow this logic with a non-happy path:</li>
|
||||
</ul>
|
||||
<pre><code class="language-go">if s != "" {
|
||||
// ...
|
||||
} else {
|
||||
return errors.New("empty string")
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s">""</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"empty string"</span><span class="p">)</span>
|
||||
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Here, an empty <code>s</code> represents the non-happy path. Hence, we should flip the
|
||||
condition like so:</p>
|
||||
<pre><code class="language-go">if s == "" {
|
||||
return errors.New("empty string")
|
||||
}
|
||||
// ...
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="k">if</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">""</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"empty string"</span><span class="p">)</span>
|
||||
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="p">}</span>
|
||||
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="c1">// ...</span>
|
||||
</span></code></pre></div>
|
||||
<p>Writing readable code is an important challenge for every developer. Striving to reduce the number of nested blocks, aligning the happy path on the left, and returning as early as possible are concrete means to improve our code’s readability.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/2-nested-code/main.go">Source code</a></p>
|
||||
<h3 id="misusing-init-functions-3">Misusing init functions (#3)</h3>
|
||||
|
|
@ -2364,14 +2383,14 @@ What’s the main problem if we overuse interfaces? The answer is that they make
|
|||
<p><strong>TL;DR</strong>: Using type embedding can also help avoid boilerplate code; however, ensure that doing so doesn’t lead to visibility issues where some fields should have remained hidden.</p>
|
||||
<p>When creating a struct, Go offers the option to embed types. But this can sometimes lead to unexpected behaviors if we don’t understand all the implications of type embedding. Throughout this section, we look at how to embed types, what these bring, and the possible issues.</p>
|
||||
<p>In Go, a struct field is called embedded if it’s declared without a name. For example,</p>
|
||||
<pre><code class="language-cgo">type Foo struct {
|
||||
Bar // Embedded field
|
||||
}
|
||||
|
||||
type Bar struct {
|
||||
Baz int
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="kd">type</span><span class="w"> </span><span class="nx">Foo</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="w"> </span><span class="nx">Bar</span><span class="w"> </span><span class="c1">// Embedded field</span>
|
||||
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="p">}</span>
|
||||
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a>
|
||||
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="kd">type</span><span class="w"> </span><span class="nx">Bar</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="nx">Baz</span><span class="w"> </span><span class="kt">int</span>
|
||||
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>In the <code>Foo</code> struct, the <code>Bar</code> type is declared without an associated name; hence, it’s an embedded field.</p>
|
||||
<p>We use embedding to promote the fields and methods of an embedded type. Because Bar contains a Baz field, this field is
|
||||
promoted to <code>Foo</code>. Therefore, Baz becomes available from Foo.</p>
|
||||
|
|
@ -2387,47 +2406,47 @@ promoted to <code>Foo</code>. Therefore, Baz becomes available from Foo.</p>
|
|||
* An unexported struct holds the configuration: options.
|
||||
* Each option is a function that returns the same type: <code>type Option func(options *options)</code> error. For example, <code>WithPort</code> accepts an <code>int</code> argument that represents the port and returns an <code>Option</code> type that represents how to update the <code>options</code> struct.</p>
|
||||
<p><img alt="" src="img/options.png" /></p>
|
||||
<pre><code class="language-go">type options struct {
|
||||
port *int
|
||||
}
|
||||
|
||||
type Option func(options *options) error
|
||||
|
||||
func WithPort(port int) Option {
|
||||
return func(options *options) error {
|
||||
if port < 0 {
|
||||
return errors.New("port should be positive")
|
||||
}
|
||||
options.port = &port
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewServer(addr string, opts ...Option) ( *http.Server, error) { <1>
|
||||
var options options <2>
|
||||
for _, opt := range opts { <3>
|
||||
err := opt(&options) <4>
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// At this stage, the options struct is built and contains the config
|
||||
// Therefore, we can implement our logic related to port configuration
|
||||
var port int
|
||||
if options.port == nil {
|
||||
port = defaultHTTPPort
|
||||
} else {
|
||||
if *options.port == 0 {
|
||||
port = randomPort()
|
||||
} else {
|
||||
port = *options.port
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="kd">type</span><span class="w"> </span><span class="nx">options</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="o">*</span><span class="kt">int</span>
|
||||
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="p">}</span>
|
||||
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a>
|
||||
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="kd">type</span><span class="w"> </span><span class="nx">Option</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">options</span><span class="w"> </span><span class="o">*</span><span class="nx">options</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>
|
||||
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a>
|
||||
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="kd">func</span><span class="w"> </span><span class="nx">WithPort</span><span class="p">(</span><span class="nx">port</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="nx">Option</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">options</span><span class="w"> </span><span class="o">*</span><span class="nx">options</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"port should be positive"</span><span class="p">)</span>
|
||||
</span><span id="__span-5-11"><a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-12"><a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a><span class="w"> </span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">&</span><span class="nx">port</span>
|
||||
</span><span id="__span-5-13"><a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-5-14"><a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-15"><a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a><span class="p">}</span>
|
||||
</span><span id="__span-5-16"><a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a>
|
||||
</span><span id="__span-5-17"><a id="__codelineno-5-17" name="__codelineno-5-17" href="#__codelineno-5-17"></a><span class="kd">func</span><span class="w"> </span><span class="nx">NewServer</span><span class="p">(</span><span class="nx">addr</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">opts</span><span class="w"> </span><span class="o">...</span><span class="nx">Option</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Server</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p"><</span><span class="mi">1</span><span class="p">></span>
|
||||
</span><span id="__span-5-18"><a id="__codelineno-5-18" name="__codelineno-5-18" href="#__codelineno-5-18"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">options</span><span class="w"> </span><span class="nx">options</span><span class="w"> </span><span class="p"><</span><span class="mi">2</span><span class="p">></span>
|
||||
</span><span id="__span-5-19"><a id="__codelineno-5-19" name="__codelineno-5-19" href="#__codelineno-5-19"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">opt</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">opts</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p"><</span><span class="mi">3</span><span class="p">></span>
|
||||
</span><span id="__span-5-20"><a id="__codelineno-5-20" name="__codelineno-5-20" href="#__codelineno-5-20"></a><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">opt</span><span class="p">(</span><span class="o">&</span><span class="nx">options</span><span class="p">)</span><span class="w"> </span><span class="p"><</span><span class="mi">4</span><span class="p">></span>
|
||||
</span><span id="__span-5-21"><a id="__codelineno-5-21" name="__codelineno-5-21" href="#__codelineno-5-21"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-22"><a id="__codelineno-5-22" name="__codelineno-5-22" href="#__codelineno-5-22"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-5-23"><a id="__codelineno-5-23" name="__codelineno-5-23" href="#__codelineno-5-23"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-24"><a id="__codelineno-5-24" name="__codelineno-5-24" href="#__codelineno-5-24"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-25"><a id="__codelineno-5-25" name="__codelineno-5-25" href="#__codelineno-5-25"></a>
|
||||
</span><span id="__span-5-26"><a id="__codelineno-5-26" name="__codelineno-5-26" href="#__codelineno-5-26"></a><span class="w"> </span><span class="c1">// At this stage, the options struct is built and contains the config</span>
|
||||
</span><span id="__span-5-27"><a id="__codelineno-5-27" name="__codelineno-5-27" href="#__codelineno-5-27"></a><span class="w"> </span><span class="c1">// Therefore, we can implement our logic related to port configuration</span>
|
||||
</span><span id="__span-5-28"><a id="__codelineno-5-28" name="__codelineno-5-28" href="#__codelineno-5-28"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="kt">int</span>
|
||||
</span><span id="__span-5-29"><a id="__codelineno-5-29" name="__codelineno-5-29" href="#__codelineno-5-29"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-30"><a id="__codelineno-5-30" name="__codelineno-5-30" href="#__codelineno-5-30"></a><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">defaultHTTPPort</span>
|
||||
</span><span id="__span-5-31"><a id="__codelineno-5-31" name="__codelineno-5-31" href="#__codelineno-5-31"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-32"><a id="__codelineno-5-32" name="__codelineno-5-32" href="#__codelineno-5-32"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">*</span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-33"><a id="__codelineno-5-33" name="__codelineno-5-33" href="#__codelineno-5-33"></a><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">randomPort</span><span class="p">()</span>
|
||||
</span><span id="__span-5-34"><a id="__codelineno-5-34" name="__codelineno-5-34" href="#__codelineno-5-34"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-5-35"><a id="__codelineno-5-35" name="__codelineno-5-35" href="#__codelineno-5-35"></a><span class="w"> </span><span class="nx">port</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">*</span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span>
|
||||
</span><span id="__span-5-36"><a id="__codelineno-5-36" name="__codelineno-5-36" href="#__codelineno-5-36"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-37"><a id="__codelineno-5-37" name="__codelineno-5-37" href="#__codelineno-5-37"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-5-38"><a id="__codelineno-5-38" name="__codelineno-5-38" href="#__codelineno-5-38"></a>
|
||||
</span><span id="__span-5-39"><a id="__codelineno-5-39" name="__codelineno-5-39" href="#__codelineno-5-39"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-5-40"><a id="__codelineno-5-40" name="__codelineno-5-40" href="#__codelineno-5-40"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>The functional options pattern provides a handy and API-friendly way to handle options. Although the builder pattern can be a valid option, it has some minor downsides (having to pass a config struct that can be empty or a less handy way to handle error management) that tend to make the functional options pattern the idiomatic way to deal with these kind of problems in Go.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/11-functional-options/">Source code</a></p>
|
||||
<h3 id="project-misorganization-project-structure-and-package-organization-12">Project misorganization (project structure and package organization) (#12)</h3>
|
||||
|
|
@ -2481,19 +2500,19 @@ Meanwhile, we should also look at golangci-lint (https://github.com/golangci/ go
|
|||
<h3 id="neglecting-integer-overflows-18">Neglecting integer overflows (#18)</h3>
|
||||
<p><strong>TL;DR</strong>: Because integer overflows and underflows are handled silently in Go, you can implement your own functions to catch them.</p>
|
||||
<p>In Go, an integer overflow that can be detected at compile time generates a compila- tion error. For example,</p>
|
||||
<pre><code class="language-cgo">var counter int32 = math.MaxInt32 + 1
|
||||
</code></pre>
|
||||
<pre><code class="language-shell">constant 2147483648 overflows int32
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>var counter int32 = math.MaxInt32 + 1
|
||||
</span></code></pre></div>
|
||||
<div class="language-shell highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>constant<span class="w"> </span><span class="m">2147483648</span><span class="w"> </span>overflows<span class="w"> </span>int32
|
||||
</span></code></pre></div>
|
||||
<p>However, at run time, an integer overflow or underflow is silent; this does not lead to an application panic. It is essential to keep this behavior in mind, because it can lead to sneaky bugs (for example, an integer increment or addition of positive integers that leads to a negative result).</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/18-integer-overflows">Source code</a></p>
|
||||
<h3 id="not-understanding-floating-points-19">Not understanding floating-points (#19)</h3>
|
||||
<p><strong>TL;DR</strong>: Making floating-point comparisons within a given delta can ensure that your code is portable. When performing addition or subtraction, group the operations with a similar order of magnitude to favor accuracy. Also, perform multiplication and division before addition and subtraction.</p>
|
||||
<p>In Go, there are two floating-point types (if we omit imaginary numbers): float32 and float64. The concept of a floating point was invented to solve the major problem with integers: their inability to represent fractional values. To avoid bad surprises, we need to know that floating-point arithmetic is an approximation of real arithmetic.</p>
|
||||
<p>For that, we’ll look at a multiplication example:</p>
|
||||
<pre><code class="language-go">var n float32 = 1.0001
|
||||
fmt.Println(n * n)
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="kt">float32</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mf">1.0001</span>
|
||||
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">n</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">n</span><span class="p">)</span>
|
||||
</span></code></pre></div>
|
||||
<p>We may expect this code to print the result of 1.0001 * 1.0001 = 1.00020001, right? However, running it on most x86 processors prints 1.0002, instead.</p>
|
||||
<p>Because Go’s <code>float32</code> and <code>float64</code> types are approximations, we have to bear a few rules in mind:
|
||||
* When comparing two floating-point numbers, check that their difference is within an acceptable range.
|
||||
|
|
@ -2589,14 +2608,14 @@ One additional note: we must remember that the standard library has some exist-
|
|||
<h3 id="ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays-31">Ignoring how arguments are evaluated in <code>range</code> loops (channels and arrays) (#31)</h3>
|
||||
<p><strong>TL;DR</strong>: Understanding that the expression passed to the <code>range</code> operator is evaluated only once before the beginning of the loop can help you avoid common mistakes such as inefficient assignment in channel or slice iteration.</p>
|
||||
<p>The range loop evaluates the provided expression only once, before the beginning of the loop, by doing a copy (regardless of the type). We should remember this behavior to avoid common mistakes that might, for example, lead us to access the wrong element. For example:</p>
|
||||
<pre><code class="language-go">a := [3]int{0, 1, 2}
|
||||
for i, v := range a {
|
||||
a[2] = 10
|
||||
if i == 2 {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="nx">a</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">}</span>
|
||||
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="nx">a</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">10</span>
|
||||
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span>
|
||||
</span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-9-7"><a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>This code updates the last index to 10. However, if we run this code, it does not print 10; it prints 2.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/31-range-loop-arg-evaluation/">Source code</a></p>
|
||||
<h3 id="ignoring-the-impacts-of-using-pointer-elements-in-range-loops-32">Ignoring the impacts of using pointer elements in <code>range</code> loops (#32)</h3>
|
||||
|
|
@ -2615,73 +2634,73 @@ for i, v := range a {
|
|||
<h3 id="ignoring-how-the-break-statement-works-34">Ignoring how the <code>break</code> statement works (#34)</h3>
|
||||
<p><strong>TL;DR</strong>: Using <code>break</code> or <code>continue</code> with a label enforces breaking a specific statement. This can be helpful with <code>switch</code> or <code>select</code> statements inside loops.</p>
|
||||
<p>A break statement is commonly used to terminate the execution of a loop. When loops are used in conjunction with switch or select, developers frequently make the mistake of breaking the wrong statement. For example:</p>
|
||||
<pre><code class="language-go">for i := 0; i < 5; i++ {
|
||||
fmt.Printf("%d ", i)
|
||||
|
||||
switch i {
|
||||
default:
|
||||
case 2:
|
||||
break
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">)</span>
|
||||
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a>
|
||||
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="k">default</span><span class="p">:</span>
|
||||
</span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span>
|
||||
</span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="w"> </span><span class="k">break</span>
|
||||
</span><span id="__span-10-8"><a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-10-9"><a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>The break statement doesn’t terminate the <code>for</code> loop: it terminates the <code>switch</code> statement, instead. Hence, instead of iterating from 0 to 2, this code iterates from 0 to 4: <code>0 1 2 3 4</code>.</p>
|
||||
<p>One essential rule to keep in mind is that a <code>break</code> statement terminates the execu- tion of the innermost <code>for</code>, <code>switch</code>, or <code>select</code> statement. In the previous example, it terminates the <code>switch</code> statement.</p>
|
||||
<p>To break the loop instead of the <code>switch</code> statement, the most idiomatic way is to use a label:</p>
|
||||
<pre><code class="language-go">loop:
|
||||
for i := 0; i < 5; i++ {
|
||||
fmt.Printf("%d ", i)
|
||||
|
||||
switch i {
|
||||
default:
|
||||
case 2:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="nx">loop</span><span class="p">:</span>
|
||||
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%d "</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">)</span>
|
||||
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a>
|
||||
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a><span class="w"> </span><span class="k">default</span><span class="p">:</span>
|
||||
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span>
|
||||
</span><span id="__span-11-8"><a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="w"> </span><span class="k">break</span><span class="w"> </span><span class="nx">loop</span>
|
||||
</span><span id="__span-11-9"><a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-11-10"><a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Here, we associate the <code>loop</code> label with the <code>for</code> loop. Then, because we provide the <code>loop</code> label to the <code>break</code> statement, it breaks the loop, not the switch. Therefore, this new version will print <code>0 1 2</code>, as we expected.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/34-break/main.go">Source code</a></p>
|
||||
<h3 id="using-defer-inside-a-loop-35">Using <code>defer</code> inside a loop (#35)</h3>
|
||||
<p><strong>TL;DR</strong>: Extracting loop logic inside a function leads to executing a <code>defer</code> statement at the end of each iteration.</p>
|
||||
<p>The <code>defer</code> statement delays a call’s execution until the surrounding function returns. It’s mainly used to reduce boilerplate code. For example, if a resource has to be closed eventually, we can use <code>defer</code> to avoid repeating the closure calls before every single <code>return</code>.</p>
|
||||
<p>One common mistake with <code>defer</code> is to forget that it schedules a function call when the <em>surrounding</em> function returns. For example:</p>
|
||||
<pre><code class="language-go">func readFiles(ch <-chan string) error {
|
||||
for path := range ch {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// Do something with file
|
||||
}
|
||||
return nil
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">readFiles</span><span class="p">(</span><span class="nx">ch</span><span class="w"> </span><span class="o"><-</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">path</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="w"> </span><span class="nx">file</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="nx">path</span><span class="p">)</span>
|
||||
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-12-5"><a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-12-6"><a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-12-7"><a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a>
|
||||
</span><span id="__span-12-8"><a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">file</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span>
|
||||
</span><span id="__span-12-9"><a id="__codelineno-12-9" name="__codelineno-12-9" href="#__codelineno-12-9"></a>
|
||||
</span><span id="__span-12-10"><a id="__codelineno-12-10" name="__codelineno-12-10" href="#__codelineno-12-10"></a><span class="w"> </span><span class="c1">// Do something with file</span>
|
||||
</span><span id="__span-12-11"><a id="__codelineno-12-11" name="__codelineno-12-11" href="#__codelineno-12-11"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-12-12"><a id="__codelineno-12-12" name="__codelineno-12-12" href="#__codelineno-12-12"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-12-13"><a id="__codelineno-12-13" name="__codelineno-12-13" href="#__codelineno-12-13"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>The <code>defer</code> calls are executed not during each loop iteration but when the <code>readFiles</code> function returns. If <code>readFiles</code> doesn’t return, the file descriptors will be kept open forever, causing leaks.</p>
|
||||
<p>One common option to fix this problem is to create a surrounding function after <code>defer</code>, called during each iteration:</p>
|
||||
<pre><code class="language-go">func readFiles(ch <-chan string) error {
|
||||
for path := range ch {
|
||||
if err := readFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFile(path string) error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// Do something with file
|
||||
return nil
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">readFiles</span><span class="p">(</span><span class="nx">ch</span><span class="w"> </span><span class="o"><-</span><span class="kd">chan</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">path</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">readFile</span><span class="p">(</span><span class="nx">path</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-13-5"><a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-13-6"><a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-13-7"><a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-13-8"><a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a><span class="p">}</span>
|
||||
</span><span id="__span-13-9"><a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a>
|
||||
</span><span id="__span-13-10"><a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a><span class="kd">func</span><span class="w"> </span><span class="nx">readFile</span><span class="p">(</span><span class="nx">path</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-13-11"><a id="__codelineno-13-11" name="__codelineno-13-11" href="#__codelineno-13-11"></a><span class="w"> </span><span class="nx">file</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="nx">path</span><span class="p">)</span>
|
||||
</span><span id="__span-13-12"><a id="__codelineno-13-12" name="__codelineno-13-12" href="#__codelineno-13-12"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-13-13"><a id="__codelineno-13-13" name="__codelineno-13-13" href="#__codelineno-13-13"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-13-14"><a id="__codelineno-13-14" name="__codelineno-13-14" href="#__codelineno-13-14"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-13-15"><a id="__codelineno-13-15" name="__codelineno-13-15" href="#__codelineno-13-15"></a>
|
||||
</span><span id="__span-13-16"><a id="__codelineno-13-16" name="__codelineno-13-16" href="#__codelineno-13-16"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">file</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span>
|
||||
</span><span id="__span-13-17"><a id="__codelineno-13-17" name="__codelineno-13-17" href="#__codelineno-13-17"></a>
|
||||
</span><span id="__span-13-18"><a id="__codelineno-13-18" name="__codelineno-13-18" href="#__codelineno-13-18"></a><span class="w"> </span><span class="c1">// Do something with file</span>
|
||||
</span><span id="__span-13-19"><a id="__codelineno-13-19" name="__codelineno-13-19" href="#__codelineno-13-19"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-13-20"><a id="__codelineno-13-20" name="__codelineno-13-20" href="#__codelineno-13-20"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Another solution is to make the <code>readFile</code> function a closure but intrinsically, this remains the same solution: adding another surrounding function to execute the <code>defer</code> calls during each iteration.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/35-defer-loop/main.go">Source code</a></p>
|
||||
<h2 id="strings">Strings</h2>
|
||||
|
|
@ -2701,19 +2720,19 @@ func readFile(path string) error {
|
|||
<p><strong>TL;DR</strong>: Iterating on a string with the <code>range</code> operator iterates on the runes with the index corresponding to the starting index of the rune’s byte sequence. To access a specific rune index (such as the third rune), convert the string into a <code>[]rune</code>.</p>
|
||||
<p>Iterating on a string is a common operation for developers. Perhaps we want to per- form an operation for each rune in the string or implement a custom function to search for a specific substring. In both cases, we have to iterate on the different runes of a string. But it’s easy to get confused about how iteration works.</p>
|
||||
<p>For example, consider the following example:</p>
|
||||
<pre><code class="language-go">s := "hêllo"
|
||||
for i := range s {
|
||||
fmt.Printf("position %d: %c\n", i, s[i])
|
||||
}
|
||||
fmt.Printf("len=%d\n", len(s))
|
||||
</code></pre>
|
||||
<pre><code>position 0: h
|
||||
position 1: Ã
|
||||
position 3: l
|
||||
position 4: l
|
||||
position 5: o
|
||||
len=6
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">"hêllo"</span>
|
||||
</span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"position %d: %c\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span>
|
||||
</span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="p">}</span>
|
||||
</span><span id="__span-14-5"><a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"len=%d\n"</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">))</span>
|
||||
</span></code></pre></div>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a>position 0: h
|
||||
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a>position 1: Ã
|
||||
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>position 3: l
|
||||
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a>position 4: l
|
||||
</span><span id="__span-15-5"><a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a>position 5: o
|
||||
</span><span id="__span-15-6"><a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a>len=6
|
||||
</span></code></pre></div>
|
||||
<p>Let's highlight three points that might be confusing:</p>
|
||||
<ul>
|
||||
<li>The second rune is à in the output instead of ê.</li>
|
||||
|
|
@ -2725,30 +2744,30 @@ len=6
|
|||
<p><img alt="" src="img/rune.png" /></p>
|
||||
<p>Printing <code>s[i]</code> doesn’t print the ith rune; it prints the UTF-8 representation of the byte at index <code>i</code>. Hence, we printed "hÃllo" instead of "hêllo".</p>
|
||||
<p>If we want to print all the different runes, we can either use the value element of the <code>range</code> operator:</p>
|
||||
<pre><code class="language-go">s := "hêllo"
|
||||
for i, r := range s {
|
||||
fmt.Printf("position %d: %c\n", i, r)
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">"hêllo"</span>
|
||||
</span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"position %d: %c\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="p">)</span>
|
||||
</span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Or, we can convert the string into a slice of runes and iterate over it:</p>
|
||||
<pre><code class="language-cgo">s := "hêllo"
|
||||
runes := []rune(s)
|
||||
for i, r := range runes {
|
||||
fmt.Printf("position %d: %c\n", i, r)
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a>s := "hêllo"
|
||||
</span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>runes := []rune(s)
|
||||
</span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>for i, r := range runes {
|
||||
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a> fmt.Printf("position %d: %c\n", i, r)
|
||||
</span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a>}
|
||||
</span></code></pre></div>
|
||||
<p>Note that this solution introduces a run-time overhead compared to the previous one. Indeed, converting a string into a slice of runes requires allocating an additional slice and converting the bytes into runes: an O(n) time complexity with n the number of bytes in the string. Therefore, if we want to iterate over all the runes, we should use the first solution.</p>
|
||||
<p>However, if we want to access the ith rune of a string with the first option, we don’t have access to the rune index; rather, we know the starting index of a rune in the byte sequence.</p>
|
||||
<pre><code class="language-cgo">s := "hêllo"
|
||||
r := []rune(s)[4]
|
||||
fmt.Printf("%c\n", r) // o
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>s := "hêllo"
|
||||
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>r := []rune(s)[4]
|
||||
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>fmt.Printf("%c\n", r) // o
|
||||
</span></code></pre></div>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/37-string-iteration/main.go">Source code</a></p>
|
||||
<h3 id="misusing-trim-functions-38">Misusing trim functions (#38)</h3>
|
||||
<p><strong>TL;DR</strong>: <code>strings.TrimRight</code>/<code>strings.TrimLeft</code> removes all the trailing/leading runes contained in a given set, whereas <code>strings.TrimSuffix</code>/<code>strings.TrimPrefix</code> returns a string without a provided suffix/prefix.</p>
|
||||
<p>For example:</p>
|
||||
<pre><code class="language-cgo">fmt.Println(strings.TrimRight("123oxo", "xo"))
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a>fmt.Println(strings.TrimRight("123oxo", "xo"))
|
||||
</span></code></pre></div>
|
||||
<p>The example prints 123:</p>
|
||||
<p><img alt="" src="img/trim.png" /></p>
|
||||
<p>Conversely, <code>strings.TrimLeft</code> removes all the leading runes contained in a set.</p>
|
||||
|
|
@ -2757,49 +2776,49 @@ fmt.Printf("%c\n", r) // o
|
|||
<h3 id="under-optimized-strings-concatenation-39">Under-optimized strings concatenation (#39)</h3>
|
||||
<p><strong>TL;DR</strong>: Concatenating a list of strings should be done with <code>strings.Builder</code> to prevent allocating a new string during each iteration.</p>
|
||||
<p>Let’s consider a <code>concat</code> function that concatenates all the string elements of a slice using the <code>+=</code> operator:</p>
|
||||
<pre><code class="language-go">func concat(values []string) string {
|
||||
s := ""
|
||||
for _, value := range values {
|
||||
s += value
|
||||
}
|
||||
return s
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">concat</span><span class="p">(</span><span class="nx">values</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">""</span>
|
||||
</span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">values</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-20-4"><a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">value</span>
|
||||
</span><span id="__span-20-5"><a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-20-6"><a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">s</span>
|
||||
</span><span id="__span-20-7"><a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>During each iteration, the <code>+=</code> operator concatenates <code>s</code> with the value string. At first sight, this function may not look wrong. But with this implementation, we forget one of the core characteristics of a string: its immutability. Therefore, each iteration doesn’t update <code>s</code>; it reallocates a new string in memory, which significantly impacts the performance of this function.</p>
|
||||
<p>Fortunately, there is a solution to deal with this problem, using <code>strings.Builder</code>:</p>
|
||||
<pre><code class="language-go">func concat(values []string) string {
|
||||
sb := strings.Builder{}
|
||||
for _, value := range values {
|
||||
_, _ = sb.WriteString(value)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">concat</span><span class="p">(</span><span class="nx">values</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="w"> </span><span class="nx">sb</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nx">Builder</span><span class="p">{}</span>
|
||||
</span><span id="__span-21-3"><a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">values</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-21-4"><a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sb</span><span class="p">.</span><span class="nx">WriteString</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span>
|
||||
</span><span id="__span-21-5"><a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-21-6"><a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">sb</span><span class="p">.</span><span class="nx">String</span><span class="p">()</span>
|
||||
</span><span id="__span-21-7"><a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>During each iteration, we constructed the resulting string by calling the <code>WriteString</code> method that appends the content of value to its internal buffer, hence minimizing memory copying.</p>
|
||||
<blockquote>
|
||||
<p>[!NOTE]
|
||||
<code>WriteString</code> returns an error as the second output, but we purposely ignore it. Indeed, this method will never return a non-nil error. So what’s the purpose of this method returning an error as part of its signature? <code>strings.Builder</code> imple- ments the <code>io.StringWriter</code> interface, which contains a single method: <code>WriteString(s string) (n int, err error)</code>. Hence, to comply with this interface, <code>WriteString</code> must return an error.</p>
|
||||
</blockquote>
|
||||
<p>Internally, <code>strings.Builder</code> holds a byte slice. Each call to <code>WriteString</code> results in a call to append on this slice. There are two impacts. First, this struct shouldn’t be used concurrently, as the calls to <code>append</code> would lead to race conditions. The second impact is something that we saw in <a href="#inefficient-slice-initialization-21">mistake #21, "Inefficient slice initialization"</a>: if the future length of a slice is already known, we should preallocate it. For that purpose, <code>strings.Builder</code> exposes a method <code>Grow(n int)</code> to guarantee space for another <code>n</code> bytes:</p>
|
||||
<pre><code class="language-go">func concat(values []string) string {
|
||||
total := 0
|
||||
for i := 0; i < len(values); i++ {
|
||||
total += len(values[i])
|
||||
}
|
||||
|
||||
sb := strings.Builder{}
|
||||
sb.Grow(total) (2)
|
||||
for _, value := range values {
|
||||
_, _ = sb.WriteString(value)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">concat</span><span class="p">(</span><span class="nx">values</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="w"> </span><span class="nx">total</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span>
|
||||
</span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">values</span><span class="p">);</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-22-4"><a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="w"> </span><span class="nx">total</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">values</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span>
|
||||
</span><span id="__span-22-5"><a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-22-6"><a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a>
|
||||
</span><span id="__span-22-7"><a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a><span class="w"> </span><span class="nx">sb</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">strings</span><span class="p">.</span><span class="nx">Builder</span><span class="p">{}</span>
|
||||
</span><span id="__span-22-8"><a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a><span class="w"> </span><span class="nx">sb</span><span class="p">.</span><span class="nx">Grow</span><span class="p">(</span><span class="nx">total</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
</span><span id="__span-22-9"><a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">values</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-22-10"><a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sb</span><span class="p">.</span><span class="nx">WriteString</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span>
|
||||
</span><span id="__span-22-11"><a id="__codelineno-22-11" name="__codelineno-22-11" href="#__codelineno-22-11"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-22-12"><a id="__codelineno-22-12" name="__codelineno-22-12" href="#__codelineno-22-12"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">sb</span><span class="p">.</span><span class="nx">String</span><span class="p">()</span>
|
||||
</span><span id="__span-22-13"><a id="__codelineno-22-13" name="__codelineno-22-13" href="#__codelineno-22-13"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Let’s run a benchmark to compare the three versions (v1 using <code>+=</code>; v2 using <code>strings.Builder{}</code> without preallocation; and v3 using <code>strings.Builder{}</code> with pre- allocation). The input slice contains 1,000 strings, and each string contains 1,000 bytes:</p>
|
||||
<pre><code>BenchmarkConcatV1-4 16 72291485 ns/op
|
||||
BenchmarkConcatV2-4 1188 878962 ns/op
|
||||
BenchmarkConcatV3-4 5922 190340 ns/op
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a>BenchmarkConcatV1-4 16 72291485 ns/op
|
||||
</span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a>BenchmarkConcatV2-4 1188 878962 ns/op
|
||||
</span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a>BenchmarkConcatV3-4 5922 190340 ns/op
|
||||
</span></code></pre></div>
|
||||
<p>As we can see, the latest version is by far the most efficient: 99% faster than v1 and 78% faster than v2.</p>
|
||||
<p><code>strings.Builder</code> is the recommended solution to concatenate a list of strings. Usually, this solution should be used within a loop. Indeed, if we just have to concate- nate a few strings (such as a name and a surname), using <code>strings.Builder</code> is not rec- ommended as doing so will make the code a bit less readable than using the <code>+=</code> operator or <code>fmt.Sprintf</code>.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/39-string-concat/">Source code</a></p>
|
||||
|
|
@ -2821,12 +2840,12 @@ BenchmarkConcatV3-4 5922 190340 ns/op
|
|||
<ul>
|
||||
<li>If the method needs to mutate the receiver. This rule is also valid if the receiver is a slice and a method needs to append elements:</li>
|
||||
</ul>
|
||||
<p>```cgo
|
||||
type slice []int</p>
|
||||
<p>func (s <em>slice) add(element int) {
|
||||
</em>s = append(*s, element)
|
||||
}
|
||||
```</p>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a>type slice []int
|
||||
</span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a>
|
||||
</span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a>func (s *slice) add(element int) {
|
||||
</span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a> *s = append(*s, element)
|
||||
</span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a>}
|
||||
</span></code></pre></div>
|
||||
<ul>
|
||||
<li>If the method receiver contains a field that cannot be copied: for example, a type part of the sync package (see <a href="#copying-a-sync-type--74-">#74, “Copying a sync type”</a>).</li>
|
||||
</ul>
|
||||
|
|
@ -2852,31 +2871,31 @@ BenchmarkConcatV3-4 5922 190340 ns/op
|
|||
<p><strong>TL;DR</strong>: Using named result parameters can be an efficient way to improve the readability of a function/method, especially if multiple result parameters have the same type. In some cases, this approach can also be convenient because named result parameters are initialized to their zero value. But be cautious about potential side effects.</p>
|
||||
<p>When we return parameters in a function or a method, we can attach names to these parameters and use them as regular variables. When a result parameter is named, it’s initialized to its zero value when the function/method begins. With named result parameters, we can also call a naked return statement (without argu- ments). In that case, the current values of the result parameters are used as the returned values.</p>
|
||||
<p>Here’s an example that uses a named result parameter <code>b</code>:</p>
|
||||
<pre><code class="language-go">func f(a int) (b int) {
|
||||
b = a
|
||||
return
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">f</span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">b</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a><span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">a</span>
|
||||
</span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a><span class="w"> </span><span class="k">return</span>
|
||||
</span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>In this example, we attach a name to the result parameter: <code>b</code>. When we call return without arguments, it returns the current value of <code>b</code>.</p>
|
||||
<p>In some cases, named result parameters can also increase readability: for example, if two parameters have the same type. In other cases, they can also be used for convenience. Therefore, we should use named result parameters sparingly when there’s a clear benefit.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/43-named-result-parameters/main.go">Source code</a></p>
|
||||
<h3 id="unintended-side-effects-with-named-result-parameters-44">Unintended side effects with named result parameters (#44)</h3>
|
||||
<p><strong>TL;DR</strong>: See <a href="#never-using-named-result-parameters-43">#43</a>.</p>
|
||||
<p>We mentioned why named result parameters can be useful in some situations. But as these result parameters are initialized to their zero value, using them can sometimes lead to subtle bugs if we’re not careful enough. For example, can you spot what’s wrong with this code?</p>
|
||||
<pre><code class="language-go">func (l loc) getCoordinates(ctx context.Context, address string) (
|
||||
lat, lng float32, err error) {
|
||||
isValid := l.validateAddress(address) (1)
|
||||
if !isValid {
|
||||
return 0, 0, errors.New("invalid address")
|
||||
}
|
||||
|
||||
if ctx.Err() != nil { (2)
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
// Get and return coordinates
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-26-1"><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">l</span><span class="w"> </span><span class="nx">loc</span><span class="p">)</span><span class="w"> </span><span class="nx">getCoordinates</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span><span class="w"> </span><span class="nx">address</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span>
|
||||
</span><span id="__span-26-2"><a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a><span class="w"> </span><span class="nx">lat</span><span class="p">,</span><span class="w"> </span><span class="nx">lng</span><span class="w"> </span><span class="kt">float32</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-26-3"><a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a><span class="w"> </span><span class="nx">isValid</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">l</span><span class="p">.</span><span class="nx">validateAddress</span><span class="p">(</span><span class="nx">address</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
</span><span id="__span-26-4"><a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">isValid</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-26-5"><a id="__codelineno-26-5" name="__codelineno-26-5" href="#__codelineno-26-5"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">errors</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">"invalid address"</span><span class="p">)</span>
|
||||
</span><span id="__span-26-6"><a id="__codelineno-26-6" name="__codelineno-26-6" href="#__codelineno-26-6"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-26-7"><a id="__codelineno-26-7" name="__codelineno-26-7" href="#__codelineno-26-7"></a>
|
||||
</span><span id="__span-26-8"><a id="__codelineno-26-8" name="__codelineno-26-8" href="#__codelineno-26-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">ctx</span><span class="p">.</span><span class="nx">Err</span><span class="p">()</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
|
||||
</span><span id="__span-26-9"><a id="__codelineno-26-9" name="__codelineno-26-9" href="#__codelineno-26-9"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-26-10"><a id="__codelineno-26-10" name="__codelineno-26-10" href="#__codelineno-26-10"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-26-11"><a id="__codelineno-26-11" name="__codelineno-26-11" href="#__codelineno-26-11"></a>
|
||||
</span><span id="__span-26-12"><a id="__codelineno-26-12" name="__codelineno-26-12" href="#__codelineno-26-12"></a><span class="w"> </span><span class="c1">// Get and return coordinates</span>
|
||||
</span><span id="__span-26-13"><a id="__codelineno-26-13" name="__codelineno-26-13" href="#__codelineno-26-13"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>The error might not be obvious at first glance. Here, the error returned in the <code>if ctx.Err() != nil</code> scope is <code>err</code>. But we haven’t assigned any value to the <code>err</code> variable. It’s still assigned to the zero value of an <code>error</code> type: <code>nil</code>. Hence, this code will always return a nil error.</p>
|
||||
<p>When using named result parameters, we must recall that each parameter is initial- ized to its zero value. As we have seen in this section, this can lead to subtle bugs that aren’t always straightforward to spot while reading code. Therefore, let’s remain cau- tious when using named result parameters, to avoid potential side effects.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/44-side-effects-named-result-parameters/main.go">Source code</a></p>
|
||||
|
|
@ -2892,66 +2911,66 @@ BenchmarkConcatV3-4 5922 190340 ns/op
|
|||
<h3 id="ignoring-how-defer-arguments-and-receivers-are-evaluated-argument-evaluation-pointer-and-value-receivers-47">Ignoring how <code>defer</code> arguments and receivers are evaluated (argument evaluation, pointer, and value receivers) (#47)</h3>
|
||||
<p><strong>TL;DR</strong>: Passing a pointer to a <code>defer</code> function and wrapping a call inside a closure are two possible solutions to overcome the immediate evaluation of arguments and receivers.</p>
|
||||
<p>In a <code>defer</code> function the arguments are evaluated right away, not once the surrounding function returns. For example, in this code, we always call <code>notify</code> and <code>incrementCounter</code> with the same status: an empty string.</p>
|
||||
<pre><code class="language-go">const (
|
||||
StatusSuccess = "success"
|
||||
StatusErrorFoo = "error_foo"
|
||||
StatusErrorBar = "error_bar"
|
||||
)
|
||||
|
||||
func f() error {
|
||||
var status string
|
||||
defer notify(status)
|
||||
defer incrementCounter(status)
|
||||
|
||||
if err := foo(); err != nil {
|
||||
status = StatusErrorFoo
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bar(); err != nil {
|
||||
status = StatusErrorBar
|
||||
return err
|
||||
}
|
||||
|
||||
status = StatusSuccess <5>
|
||||
return nil
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-27-1"><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><span class="kd">const</span><span class="w"> </span><span class="p">(</span>
|
||||
</span><span id="__span-27-2"><a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a><span class="w"> </span><span class="nx">StatusSuccess</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"success"</span>
|
||||
</span><span id="__span-27-3"><a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a><span class="w"> </span><span class="nx">StatusErrorFoo</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"error_foo"</span>
|
||||
</span><span id="__span-27-4"><a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a><span class="w"> </span><span class="nx">StatusErrorBar</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"error_bar"</span>
|
||||
</span><span id="__span-27-5"><a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a><span class="p">)</span>
|
||||
</span><span id="__span-27-6"><a id="__codelineno-27-6" name="__codelineno-27-6" href="#__codelineno-27-6"></a>
|
||||
</span><span id="__span-27-7"><a id="__codelineno-27-7" name="__codelineno-27-7" href="#__codelineno-27-7"></a><span class="kd">func</span><span class="w"> </span><span class="nx">f</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-27-8"><a id="__codelineno-27-8" name="__codelineno-27-8" href="#__codelineno-27-8"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="kt">string</span>
|
||||
</span><span id="__span-27-9"><a id="__codelineno-27-9" name="__codelineno-27-9" href="#__codelineno-27-9"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">notify</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span>
|
||||
</span><span id="__span-27-10"><a id="__codelineno-27-10" name="__codelineno-27-10" href="#__codelineno-27-10"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">incrementCounter</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span>
|
||||
</span><span id="__span-27-11"><a id="__codelineno-27-11" name="__codelineno-27-11" href="#__codelineno-27-11"></a>
|
||||
</span><span id="__span-27-12"><a id="__codelineno-27-12" name="__codelineno-27-12" href="#__codelineno-27-12"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">foo</span><span class="p">();</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-27-13"><a id="__codelineno-27-13" name="__codelineno-27-13" href="#__codelineno-27-13"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusErrorFoo</span>
|
||||
</span><span id="__span-27-14"><a id="__codelineno-27-14" name="__codelineno-27-14" href="#__codelineno-27-14"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-27-15"><a id="__codelineno-27-15" name="__codelineno-27-15" href="#__codelineno-27-15"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-27-16"><a id="__codelineno-27-16" name="__codelineno-27-16" href="#__codelineno-27-16"></a>
|
||||
</span><span id="__span-27-17"><a id="__codelineno-27-17" name="__codelineno-27-17" href="#__codelineno-27-17"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">bar</span><span class="p">();</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-27-18"><a id="__codelineno-27-18" name="__codelineno-27-18" href="#__codelineno-27-18"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusErrorBar</span>
|
||||
</span><span id="__span-27-19"><a id="__codelineno-27-19" name="__codelineno-27-19" href="#__codelineno-27-19"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-27-20"><a id="__codelineno-27-20" name="__codelineno-27-20" href="#__codelineno-27-20"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-27-21"><a id="__codelineno-27-21" name="__codelineno-27-21" href="#__codelineno-27-21"></a>
|
||||
</span><span id="__span-27-22"><a id="__codelineno-27-22" name="__codelineno-27-22" href="#__codelineno-27-22"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusSuccess</span><span class="w"> </span><span class="p"><</span><span class="mi">5</span><span class="p">></span>
|
||||
</span><span id="__span-27-23"><a id="__codelineno-27-23" name="__codelineno-27-23" href="#__codelineno-27-23"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-27-24"><a id="__codelineno-27-24" name="__codelineno-27-24" href="#__codelineno-27-24"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Indeed, we call <code>notify(status)</code> and <code>incrementCounter(status)</code> as <code>defer</code> functions. Therefore, Go will delay these calls to be executed once <code>f</code> returns with the current value of status at the stage we used defer, hence passing an empty string.</p>
|
||||
<p>Two leading options if we want to keep using <code>defer</code>.</p>
|
||||
<p>The first solution is to pass a string pointer:</p>
|
||||
<pre><code class="language-go">func f() error {
|
||||
var status string
|
||||
defer notify(&status)
|
||||
defer incrementCounter(&status)
|
||||
|
||||
// The rest of the function unchanged
|
||||
if err := foo(); err != nil {
|
||||
status = StatusErrorFoo
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bar(); err != nil {
|
||||
status = StatusErrorBar
|
||||
return err
|
||||
}
|
||||
|
||||
status = StatusSuccess
|
||||
return nil
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-28-1"><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">f</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-28-2"><a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="kt">string</span>
|
||||
</span><span id="__span-28-3"><a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">notify</span><span class="p">(</span><span class="o">&</span><span class="nx">status</span><span class="p">)</span><span class="w"> </span>
|
||||
</span><span id="__span-28-4"><a id="__codelineno-28-4" name="__codelineno-28-4" href="#__codelineno-28-4"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">incrementCounter</span><span class="p">(</span><span class="o">&</span><span class="nx">status</span><span class="p">)</span>
|
||||
</span><span id="__span-28-5"><a id="__codelineno-28-5" name="__codelineno-28-5" href="#__codelineno-28-5"></a>
|
||||
</span><span id="__span-28-6"><a id="__codelineno-28-6" name="__codelineno-28-6" href="#__codelineno-28-6"></a><span class="w"> </span><span class="c1">// The rest of the function unchanged</span>
|
||||
</span><span id="__span-28-7"><a id="__codelineno-28-7" name="__codelineno-28-7" href="#__codelineno-28-7"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">foo</span><span class="p">();</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-28-8"><a id="__codelineno-28-8" name="__codelineno-28-8" href="#__codelineno-28-8"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusErrorFoo</span>
|
||||
</span><span id="__span-28-9"><a id="__codelineno-28-9" name="__codelineno-28-9" href="#__codelineno-28-9"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-28-10"><a id="__codelineno-28-10" name="__codelineno-28-10" href="#__codelineno-28-10"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-28-11"><a id="__codelineno-28-11" name="__codelineno-28-11" href="#__codelineno-28-11"></a>
|
||||
</span><span id="__span-28-12"><a id="__codelineno-28-12" name="__codelineno-28-12" href="#__codelineno-28-12"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">bar</span><span class="p">();</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-28-13"><a id="__codelineno-28-13" name="__codelineno-28-13" href="#__codelineno-28-13"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusErrorBar</span>
|
||||
</span><span id="__span-28-14"><a id="__codelineno-28-14" name="__codelineno-28-14" href="#__codelineno-28-14"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span>
|
||||
</span><span id="__span-28-15"><a id="__codelineno-28-15" name="__codelineno-28-15" href="#__codelineno-28-15"></a><span class="w"> </span><span class="p">}</span>
|
||||
</span><span id="__span-28-16"><a id="__codelineno-28-16" name="__codelineno-28-16" href="#__codelineno-28-16"></a>
|
||||
</span><span id="__span-28-17"><a id="__codelineno-28-17" name="__codelineno-28-17" href="#__codelineno-28-17"></a><span class="w"> </span><span class="nx">status</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">StatusSuccess</span>
|
||||
</span><span id="__span-28-18"><a id="__codelineno-28-18" name="__codelineno-28-18" href="#__codelineno-28-18"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||||
</span><span id="__span-28-19"><a id="__codelineno-28-19" name="__codelineno-28-19" href="#__codelineno-28-19"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>Using <code>defer</code> evaluates the arguments right away: here, the address of status. Yes, status itself is modified throughout the function, but its address remains constant, regardless of the assignments. Hence, if <code>notify</code> or <code>incrementCounter</code> uses the value referenced by the string pointer, it will work as expected. But this solution requires changing the signature of the two functions, which may not always be possible.</p>
|
||||
<p>There’s another solution: calling a closure (an anonymous function value that references variables from outside its body) as a <code>defer</code> statement:</p>
|
||||
<pre><code class="language-cgo">func f() error {
|
||||
var status string
|
||||
defer func() {
|
||||
notify(status)
|
||||
incrementCounter(status)
|
||||
}()
|
||||
|
||||
// The rest of the function unchanged
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a>func f() error {
|
||||
</span><span id="__span-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a> var status string
|
||||
</span><span id="__span-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a> defer func() {
|
||||
</span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a> notify(status)
|
||||
</span><span id="__span-29-5"><a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a> incrementCounter(status)
|
||||
</span><span id="__span-29-6"><a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a> }()
|
||||
</span><span id="__span-29-7"><a id="__codelineno-29-7" name="__codelineno-29-7" href="#__codelineno-29-7"></a>
|
||||
</span><span id="__span-29-8"><a id="__codelineno-29-8" name="__codelineno-29-8" href="#__codelineno-29-8"></a> // The rest of the function unchanged
|
||||
</span><span id="__span-29-9"><a id="__codelineno-29-9" name="__codelineno-29-9" href="#__codelineno-29-9"></a>}
|
||||
</span></code></pre></div>
|
||||
<p>Here, we wrap the calls to both <code>notify</code> and <code>incrementCounter</code> within a closure. This closure references the status variable from outside its body. Therefore, <code>status</code> is evaluated once the closure is executed, not when we call <code>defer</code>. This solution also works and doesn’t require <code>notify</code> and <code>incrementCounter</code> to change their signature.</p>
|
||||
<p>Let's also note this behavior applies with method receiver: the receiver is evaluated immediately.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/47-defer-evaluation/">Source code</a></p>
|
||||
|
|
@ -2959,20 +2978,20 @@ func f() error {
|
|||
<h3 id="panicking-48">Panicking (#48)</h3>
|
||||
<p><strong>TL;DR</strong>: Using <code>panic</code> is an option to deal with errors in Go. However, it should only be used sparingly in unrecoverable conditions: for example, to signal a programmer error or when you fail to load a mandatory dependency.</p>
|
||||
<p>In Go, panic is a built-in function that stops the ordinary flow:</p>
|
||||
<pre><code class="language-go">func main() {
|
||||
fmt.Println("a")
|
||||
panic("foo")
|
||||
fmt.Println("b")
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-30-1"><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-30-2"><a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">"a"</span><span class="p">)</span>
|
||||
</span><span id="__span-30-3"><a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a><span class="w"> </span><span class="nb">panic</span><span class="p">(</span><span class="s">"foo"</span><span class="p">)</span>
|
||||
</span><span id="__span-30-4"><a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">"b"</span><span class="p">)</span>
|
||||
</span><span id="__span-30-5"><a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>This code prints a and then stops before printing b:</p>
|
||||
<pre><code>a
|
||||
panic: foo
|
||||
|
||||
goroutine 1 [running]:
|
||||
main.main()
|
||||
main.go:7 +0xb3
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-31-1"><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a>a
|
||||
</span><span id="__span-31-2"><a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a>panic: foo
|
||||
</span><span id="__span-31-3"><a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a>
|
||||
</span><span id="__span-31-4"><a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a>goroutine 1 [running]:
|
||||
</span><span id="__span-31-5"><a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a>main.main()
|
||||
</span><span id="__span-31-6"><a id="__codelineno-31-6" name="__codelineno-31-6" href="#__codelineno-31-6"></a> main.go:7 +0xb3
|
||||
</span></code></pre></div>
|
||||
<p>Panicking in Go should be used sparingly. There are two prominent cases, one to signal a programmer error (e.g., <a href="https://cs.opensource.google/go/go/+/refs/tags/go1.20.7:src/database/sql/sql.go;l=44"><code>sql.Register</code></a> that panics if the driver is <code>nil</code> or has already been register) and another where our application fails to create a man- datory dependency. Hence, exceptional conditions that lead us to stop the application. In most other cases, error management should be done with a function that returns a proper error type as the last return argument.</p>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/48-panic/main.go">Source code</a></p>
|
||||
<h3 id="ignoring-when-to-wrap-an-error-49">Ignoring when to wrap an error (#49)</h3>
|
||||
|
|
@ -2992,10 +3011,10 @@ main.main()
|
|||
<h3 id="comparing-an-error-value-inaccurately-51">Comparing an error value inaccurately (#51)</h3>
|
||||
<p><strong>TL;DR</strong>: If you use Go 1.13 error wrapping with the <code>%w</code> directive and <code>fmt.Errorf</code>, comparing an error against or a value has to be done using <code>errors.As</code>. Otherwise, if the returned error you want to check is wrapped, it will fail the checks.</p>
|
||||
<p>A sentinel error is an error defined as a global variable:</p>
|
||||
<pre><code class="language-cgo">import "errors"
|
||||
|
||||
var ErrFoo = errors.New("foo")
|
||||
</code></pre>
|
||||
<div class="language-text highlight"><pre><span></span><code><span id="__span-32-1"><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a>import "errors"
|
||||
</span><span id="__span-32-2"><a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a>
|
||||
</span><span id="__span-32-3"><a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a>var ErrFoo = errors.New("foo")
|
||||
</span></code></pre></div>
|
||||
<p>In general, the convention is to start with <code>Err</code> followed by the error type: here, <code>ErrFoo</code>. A sentinel error conveys an <em>expected</em> error, an error that clients will expect to check. As general guidelines:</p>
|
||||
<ul>
|
||||
<li>Expected errors should be designed as error values (sentinel errors): <code>var ErrFoo = errors.New("foo")</code>.</li>
|
||||
|
|
@ -3014,24 +3033,24 @@ var ErrFoo = errors.New("foo")
|
|||
<h3 id="not-handling-defer-errors-54">Not handling <code>defer</code> errors (#54)</h3>
|
||||
<p><strong>TL;DR</strong>: In many cases, you shouldn’t ignore an error returned by a <code>defer</code> function. Either handle it directly or propagate it to the caller, depending on the context. If you want to ignore it, use the blank identifier.</p>
|
||||
<p>Consider the following code:</p>
|
||||
<pre><code class="language-go">func f() {
|
||||
// ...
|
||||
notify() // Error handling is omitted
|
||||
}
|
||||
|
||||
func notify() error {
|
||||
// ...
|
||||
}
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-33-1"><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">f</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-33-2"><a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-33-3"><a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a><span class="w"> </span><span class="nx">notify</span><span class="p">()</span><span class="w"> </span><span class="c1">// Error handling is omitted</span>
|
||||
</span><span id="__span-33-4"><a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a><span class="p">}</span>
|
||||
</span><span id="__span-33-5"><a id="__codelineno-33-5" name="__codelineno-33-5" href="#__codelineno-33-5"></a>
|
||||
</span><span id="__span-33-6"><a id="__codelineno-33-6" name="__codelineno-33-6" href="#__codelineno-33-6"></a><span class="kd">func</span><span class="w"> </span><span class="nx">notify</span><span class="p">()</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span>
|
||||
</span><span id="__span-33-7"><a id="__codelineno-33-7" name="__codelineno-33-7" href="#__codelineno-33-7"></a><span class="w"> </span><span class="c1">// ...</span>
|
||||
</span><span id="__span-33-8"><a id="__codelineno-33-8" name="__codelineno-33-8" href="#__codelineno-33-8"></a><span class="p">}</span>
|
||||
</span></code></pre></div>
|
||||
<p>From a maintainability perspective, the code can lead to some issues. Let’s consider a new reader looking at it. This reader notices that notify returns an error but that the error isn’t handled by the parent function. How can they guess whether or not handling the error was intentional? How can they know whether the previous developer forgot to handle it or did it purposely?</p>
|
||||
<p>For these reasons, when we want to ignore an error, there's only one way to do it, using the blank identifier (<code>_</code>):</p>
|
||||
<pre><code class="language-go">_ = notify
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-34-1"><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">notify</span>
|
||||
</span></code></pre></div>
|
||||
<p>In terms of compilation and run time, this approach doesn’t change anything compared to the first piece of code. But this new version makes explicit that we aren’t interested in the error. Also, we can add a comment that indicates the rationale for why an error is ignored:</p>
|
||||
<pre><code class="language-go">// At-most once delivery.
|
||||
// Hence, it's accepted to miss some of them in case of errors.
|
||||
_ = notify()
|
||||
</code></pre>
|
||||
<div class="language-go highlight"><pre><span></span><code><span id="__span-35-1"><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="c1">// At-most once delivery.</span>
|
||||
</span><span id="__span-35-2"><a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a><span class="c1">// Hence, it's accepted to miss some of them in case of errors.</span>
|
||||
</span><span id="__span-35-3"><a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">notify</span><span class="p">()</span>
|
||||
</span></code></pre></div>
|
||||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/54-defer-errors/main.go">Source code</a></p>
|
||||
<h2 id="concurrency-foundations">Concurrency: Foundations</h2>
|
||||
<h3 id="mixing-up-concurrency-and-parallelism-55">Mixing up concurrency and parallelism (#55)</h3>
|
||||
|
|
|
|||
|
|
@ -451,6 +451,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -15,6 +15,11 @@
|
|||
<lastmod>2023-09-12</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://100go.co/external/</loc>
|
||||
<lastmod>2023-09-12</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://100go.co/jobs/</loc>
|
||||
<lastmod>2023-09-12</lastmod>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -14,6 +14,8 @@
|
|||
<link rel="prev" href="../jobs/">
|
||||
|
||||
|
||||
<link rel="next" href="../external/">
|
||||
|
||||
|
||||
<link rel="icon" href="../Go-Logo_Fuchsia.svg">
|
||||
<meta name="generator" content="mkdocs-1.5.2, mkdocs-material-9.3.1">
|
||||
|
|
@ -1331,6 +1333,25 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../external/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
External Resources
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue