mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-21 00:47:11 +08:00
5403 lines
No EOL
456 KiB
HTML
5403 lines
No EOL
456 KiB
HTML
|
||
<!doctype html>
|
||
<html lang="en" class="no-js">
|
||
<head>
|
||
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
||
<meta name="description" content="Summary of the mistakes in the 100 Go Mistakes book.">
|
||
|
||
|
||
|
||
<link rel="canonical" href="https://100go.co/">
|
||
|
||
|
||
|
||
<link rel="next" href="5-interface-pollution/">
|
||
|
||
|
||
<link rel="icon" href="img/Go-Logo_LightBlue.svg">
|
||
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.11">
|
||
|
||
|
||
|
||
<title>Common Go Mistakes - 100 Go Mistakes and How to Avoid Them</title>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="assets/stylesheets/main.7e359304.min.css">
|
||
|
||
|
||
<link rel="stylesheet" href="assets/stylesheets/palette.06af60db.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>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="stylesheets/extra.css">
|
||
|
||
<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="Common Go Mistakes - 100 Go Mistakes and How to Avoid Them" >
|
||
|
||
<meta property="og:description" content="Summary of the mistakes in the 100 Go Mistakes book." >
|
||
|
||
<meta property="og:image" content="https://100go.co/assets/images/social/index.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/" >
|
||
|
||
<meta name="twitter:card" content="summary_large_image" >
|
||
|
||
<meta name="twitter:title" content="Common Go Mistakes - 100 Go Mistakes and How to Avoid Them" >
|
||
|
||
<meta name="twitter:description" content="Summary of the mistakes in the 100 Go Mistakes book." >
|
||
|
||
<meta name="twitter:image" content="https://100go.co/assets/images/social/index.png" >
|
||
|
||
|
||
|
||
|
||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||
})(window,document,'script','dataLayer','GTM-WTPX6GZT');</script>
|
||
|
||
<link href="assets/stylesheets/glightbox.min.css" rel="stylesheet"/><style>
|
||
html.glightbox-open { overflow: initial; height: 100%; }
|
||
.gslide-title { margin-top: 0px; user-select: text; }
|
||
.gslide-desc { color: #666; user-select: text; }
|
||
.gslide-image img { background: white; }
|
||
.gscrollbar-fixer { padding-right: 15px; }
|
||
.gdesc-inner { font-size: 0.75rem; }
|
||
body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
|
||
body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
|
||
body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}</style> <script src="assets/javascripts/glightbox.min.js"></script></head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="cyan" data-md-color-accent="deep-orange">
|
||
|
||
|
||
<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="#common-go-mistakes" class="md-skip">
|
||
Skip to content
|
||
</a>
|
||
|
||
</div>
|
||
<div data-md-component="announce">
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
|
||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||
<a href="." title="100 Go Mistakes and How to Avoid Them" class="md-header__button md-logo" aria-label="100 Go Mistakes and How to Avoid Them" 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 and How to Avoid Them
|
||
</span>
|
||
</div>
|
||
<div class="md-header__topic" data-md-component="header-topic">
|
||
<span class="md-ellipsis">
|
||
|
||
Common Go Mistakes
|
||
|
||
</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="deep-orange" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
|
||
|
||
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" 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="teal" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
|
||
|
||
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" 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>
|
||
|
||
|
||
|
||
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
||
|
||
|
||
<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">
|
||
🇨🇳 简体中文
|
||
</a>
|
||
</li>
|
||
|
||
<li class="md-select__item">
|
||
<a href="/ja/" hreflang="ja" class="md-select__link">
|
||
🇯🇵 日本語
|
||
</a>
|
||
</li>
|
||
|
||
<li class="md-select__item">
|
||
<a href="/pt-br/" hreflang="pt-br" class="md-select__link">
|
||
🇧🇷 Português Brasileiro
|
||
</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">
|
||
|
||
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7 0-.24-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91 1.61 0 2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08Z"/></svg>
|
||
</a>
|
||
|
||
<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>
|
||
|
||
<div class="md-search__suggest" data-md-component="search-suggest"></div>
|
||
|
||
</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 496 512"><!--! Font Awesome Free 6.5.1 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="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
|
||
</div>
|
||
<div class="md-source__repository">
|
||
teivah/100-go-mistakes
|
||
</div>
|
||
</a>
|
||
</div>
|
||
|
||
</nav>
|
||
|
||
|
||
|
||
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
||
<div class="md-grid">
|
||
<ul class="md-tabs__list">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item md-tabs__item--active">
|
||
<a href="." class="md-tabs__link">
|
||
|
||
|
||
Go Mistakes
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="book/" class="md-tabs__link">
|
||
|
||
|
||
Book Details
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</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 md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
||
<label class="md-nav__title" for="__drawer">
|
||
<a href="." title="100 Go Mistakes and How to Avoid Them" class="md-nav__button md-logo" aria-label="100 Go Mistakes and How to Avoid Them" data-md-component="logo">
|
||
|
||
<img src="img/Go-Logo_White.svg" alt="logo">
|
||
|
||
</a>
|
||
100 Go Mistakes and How to Avoid Them
|
||
</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 496 512"><!--! Font Awesome Free 6.5.1 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="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
|
||
</div>
|
||
<div class="md-source__repository">
|
||
teivah/100-go-mistakes
|
||
</div>
|
||
</a>
|
||
</div>
|
||
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_1" checked>
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_1" id="__nav_1_label" tabindex="">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Go Mistakes
|
||
</span>
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_1_label" aria-expanded="true">
|
||
<label class="md-nav__title" for="__nav_1">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Go Mistakes
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<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">
|
||
Common Go Mistakes
|
||
</span>
|
||
|
||
|
||
|
||
|
||
<span class="md-status md-status--new" title="New content">
|
||
</span>
|
||
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<a href="." class="md-nav__link md-nav__link--active">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Common Go Mistakes
|
||
</span>
|
||
|
||
|
||
|
||
|
||
<span class="md-status md-status--new" title="New content">
|
||
</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="#code-and-project-organization" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Code and Project Organization
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Code and Project Organization">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unintended-variable-shadowing-1" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unintended variable shadowing (#1)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unnecessary-nested-code-2" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unnecessary nested code (#2)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-init-functions-3" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing init functions (#3)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#overusing-getters-and-setters-4" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Overusing getters and setters (#4)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#interface-pollution-5" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Interface pollution (#5)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#interface-on-the-producer-side-6" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Interface on the producer side (#6)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#returning-interfaces-7" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Returning interfaces (#7)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#any-says-nothing-8" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
any says nothing (#8)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-confused-about-when-to-use-generics-9" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being confused about when to use generics (#9)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-aware-of-the-possible-problems-with-type-embedding-10" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being aware of the possible problems with type embedding (#10)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-the-functional-options-pattern-11" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using the functional options pattern (#11)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#project-misorganization-project-structure-and-package-organization-12" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Project misorganization (project structure and package organization) (#12)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-utility-packages-13" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating utility packages (#13)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-package-name-collisions-14" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring package name collisions (#14)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#missing-code-documentation-15" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Missing code documentation (#15)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-linters-16" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using linters (#16)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#data-types" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Data Types
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Data Types">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-confusion-with-octal-literals-17" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating confusion with octal literals (#17)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#neglecting-integer-overflows-18" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Neglecting integer overflows (#18)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-floating-points-19" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding floating-points (#19)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-slice-length-and-capacity-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding slice length and capacity (#20)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inefficient-slice-initialization-21" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inefficient slice initialization (#21)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-confused-about-nil-vs-empty-slice-22" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being confused about nil vs. empty slice (#22)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-properly-checking-if-a-slice-is-empty-23" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not properly checking if a slice is empty (#23)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-making-slice-copies-correctly-24" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not making slice copies correctly (#24)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unexpected-side-effects-using-slice-append-25" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unexpected side effects using slice append (#25)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#slices-and-memory-leaks-26" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Slices and memory leaks (#26)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Slices and memory leaks (#26)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#leaking-capacity" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Leaking capacity
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#slice-and-pointers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Slice and pointers
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inefficient-map-initialization-27" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inefficient map initialization (#27)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#maps-and-memory-leaks-28" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Maps and memory leaks (#28)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-values-incorrectly-29" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing values incorrectly (#29)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#control-structures" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Control Structures
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Control Structures">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-that-elements-are-copied-in-range-loops-30" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring that elements are copied in range loops (#30)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays-31" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how arguments are evaluated in range loops (channels and arrays) (#31)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-the-impacts-of-using-pointer-elements-in-range-loops-32" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring the impacts of using pointer elements in range loops (#32)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration-33" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Making wrong assumptions during map iterations (ordering and map insert during iteration) (#33)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-the-break-statement-works-34" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how the break statement works (#34)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-defer-inside-a-loop-35" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using defer inside a loop (#35)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#strings" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Strings
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Strings">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-concept-of-rune-36" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the concept of rune (#36)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inaccurate-string-iteration-37" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inaccurate string iteration (#37)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-trim-functions-38" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing trim functions (#38)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#under-optimized-strings-concatenation-39" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Under-optimized strings concatenation (#39)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#useless-string-conversions-40" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Useless string conversions (#40)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#substring-and-memory-leaks-41" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Substring and memory leaks (#41)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#functions-and-methods" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Functions and Methods
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Functions and Methods">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-knowing-which-type-of-receiver-to-use-42" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not knowing which type of receiver to use (#42)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#never-using-named-result-parameters-43" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Never using named result parameters (#43)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unintended-side-effects-with-named-result-parameters-44" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unintended side effects with named result parameters (#44)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#returning-a-nil-receiver-45" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Returning a nil receiver (#45)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-a-filename-as-a-function-input-46" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using a filename as a function input (#46)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-defer-arguments-and-receivers-are-evaluated-argument-evaluation-pointer-and-value-receivers-47" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how defer arguments and receivers are evaluated (argument evaluation, pointer, and value receivers) (#47)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#error-management" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Error Management
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Error Management">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#panicking-48" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Panicking (#48)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-when-to-wrap-an-error-49" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring when to wrap an error (#49)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-an-error-type-inaccurately-50" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing an error type inaccurately (#50)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-an-error-value-inaccurately-51" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing an error value inaccurately (#51)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#handling-an-error-twice-52" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Handling an error twice (#52)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-handling-an-error-53" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not handling an error (#53)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-handling-defer-errors-54" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not handling defer errors (#54)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concurrency-foundations" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Concurrency: Foundations
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Concurrency: Foundations">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#mixing-up-concurrency-and-parallelism-55" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Mixing up concurrency and parallelism (#55)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#thinking-concurrency-is-always-faster-56" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Thinking concurrency is always faster (#56)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-puzzled-about-when-to-use-channels-or-mutexes-57" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being puzzled about when to use channels or mutexes (#57)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-race-problems-data-races-vs-race-conditions-and-the-go-memory-model-58" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding race problems (data races vs. race conditions and the Go memory model) (#58)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Not understanding race problems (data races vs. race conditions and the Go memory model) (#58)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#data-race" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Data Race
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#race-condition" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Race Condition
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-concurrency-impacts-of-a-workload-type-59" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the concurrency impacts of a workload type (#59)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misunderstanding-go-contexts-60" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misunderstanding Go contexts (#60)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Misunderstanding Go contexts (#60)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#deadline" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Deadline
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#cancellation-signals" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Cancellation signals
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#context-values" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Context values
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#catching-a-context-cancellation" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Catching a context cancellation
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concurrency-practice" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Concurrency: Practice
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Concurrency: Practice">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#propagating-an-inappropriate-context-61" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Propagating an inappropriate context (#61)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#starting-a-goroutine-without-knowing-when-to-stop-it-62" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Starting a goroutine without knowing when to stop it (#62)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-careful-with-goroutines-and-loop-variables-63" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being careful with goroutines and loop variables (#63)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#expecting-a-deterministic-behavior-using-select-and-channels-64" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Expecting a deterministic behavior using select and channels (#64)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-notification-channels-65" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using notification channels (#65)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-nil-channels-66" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using nil channels (#66)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-puzzled-about-channel-size-67" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being puzzled about channel size (#67)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-about-possible-side-effects-with-string-formatting-68" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting about possible side effects with string formatting (#68)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Forgetting about possible side effects with string formatting (#68)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#etcd-data-race" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
etcd data race
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#deadlock" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Deadlock
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-data-races-with-append-69" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating data races with append (#69)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-mutexes-inaccurately-with-slices-and-maps-70" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using mutexes inaccurately with slices and maps (#70)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-syncwaitgroup-71" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing sync.WaitGroup (#71)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-about-synccond-72" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting about sync.Cond (#72)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-errgroup-73" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using errgroup (#73)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#copying-a-sync-type-74" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Copying a sync type (#74)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#standard-library" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Standard Library
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Standard Library">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#providing-a-wrong-time-duration-75" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Providing a wrong time duration (#75)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#timeafter-and-memory-leaks-76" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
time.After and memory leaks (#76)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#json-handling-common-mistakes-77" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
JSON handling common mistakes (#77)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#common-sql-mistakes-78" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Common SQL mistakes (#78)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-closing-transient-resources-http-body-sqlrows-and-osfile-79" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not closing transient resources (HTTP body, sql.Rows, and os.File) (#79)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-the-return-statement-after-replying-to-an-http-request-80" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting the return statement after replying to an HTTP request (#80)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-the-default-http-client-and-server-81" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using the default HTTP client and server (#81)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#testing" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Testing
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Testing">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-categorizing-tests-build-tags-environment-variables-and-short-mode-82" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not categorizing tests (build tags, environment variables, and short mode) (#82)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-enabling-the-race-flag-83" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not enabling the race flag (#83)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-test-execution-modes-parallel-and-shuffle-84" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using test execution modes (parallel and shuffle) (#84)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-table-driven-tests-85" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using table-driven tests (#85)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sleeping-in-unit-tests-86" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Sleeping in unit tests (#86)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-dealing-with-the-time-api-efficiently-87" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not dealing with the time API efficiently (#87)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-testing-utility-packages-httptest-and-iotest-88" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using testing utility packages (httptest and iotest) (#88)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#writing-inaccurate-benchmarks-89" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Writing inaccurate benchmarks (#89)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-exploring-all-the-go-testing-features-90" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not exploring all the Go testing features (#90)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-fuzzing-community-mistake" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using fuzzing (community mistake)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optimizations" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Optimizations
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Optimizations">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-cpu-caches-91" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding CPU caches (#91)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#writing-concurrent-code-that-leads-to-false-sharing-92" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Writing concurrent code that leads to false sharing (#92)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-taking-into-account-instruction-level-parallelism-93" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not taking into account instruction-level parallelism (#93)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-aware-of-data-alignment-94" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being aware of data alignment (#94)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-stack-vs-heap-95" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding stack vs. heap (#95)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-knowing-how-to-reduce-allocations-api-change-compiler-optimizations-and-syncpool-96" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not knowing how to reduce allocations (API change, compiler optimizations, and sync.Pool) (#96)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-relying-on-inlining-97" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not relying on inlining (#97)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-go-diagnostics-tooling-98" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using Go diagnostics tooling (#98)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-how-the-gc-works-99" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding how the GC works (#99)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes-100" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the impacts of running Go in Docker and Kubernetes (#100)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#community" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Community
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_1_2" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_1_2" id="__nav_1_2_label" tabindex="">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Full Sections
|
||
</span>
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_1_2_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_1_2">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Full Sections
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="5-interface-pollution/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Interface pollution (#5)
|
||
</span>
|
||
|
||
|
||
|
||
|
||
<span class="md-status md-status--new" title="New content">
|
||
</span>
|
||
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="9-generics/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Being confused about when to use generics (#9)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="20-slice/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Not understanding slice length and capacity (#20)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="28-maps-memory-leaks/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Maps and memory leaks (#28)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="56-concurrency-faster/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Thinking concurrency is always faster (#56)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="89-benchmarks/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Writing inaccurate benchmarks (#89)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="92-false-sharing/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Writing concurrent code that leads to false sharing (#92)
|
||
</span>
|
||
|
||
|
||
|
||
|
||
<span class="md-status md-status--new" title="New content">
|
||
</span>
|
||
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="98-profiling-execution-tracing/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Not using Go diagnostics tooling (#98)
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_1_3" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_1_3" id="__nav_1_3_label" tabindex="">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Translations
|
||
</span>
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_1_3_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_1_3">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Translations
|
||
</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">
|
||
🇨🇳 简体中文
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="ja/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
🇯🇵 日本語
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="pt-br/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
🇧🇷 Português Brasileiro
|
||
</span>
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
Book Details
|
||
</span>
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_2">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Book Details
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="book/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
100 Go Mistakes and How to Avoid Them
|
||
</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="external/" class="md-nav__link">
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
External Resources
|
||
</span>
|
||
|
||
|
||
</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="#code-and-project-organization" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Code and Project Organization
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Code and Project Organization">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unintended-variable-shadowing-1" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unintended variable shadowing (#1)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unnecessary-nested-code-2" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unnecessary nested code (#2)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-init-functions-3" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing init functions (#3)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#overusing-getters-and-setters-4" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Overusing getters and setters (#4)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#interface-pollution-5" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Interface pollution (#5)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#interface-on-the-producer-side-6" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Interface on the producer side (#6)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#returning-interfaces-7" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Returning interfaces (#7)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#any-says-nothing-8" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
any says nothing (#8)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-confused-about-when-to-use-generics-9" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being confused about when to use generics (#9)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-aware-of-the-possible-problems-with-type-embedding-10" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being aware of the possible problems with type embedding (#10)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-the-functional-options-pattern-11" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using the functional options pattern (#11)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#project-misorganization-project-structure-and-package-organization-12" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Project misorganization (project structure and package organization) (#12)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-utility-packages-13" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating utility packages (#13)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-package-name-collisions-14" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring package name collisions (#14)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#missing-code-documentation-15" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Missing code documentation (#15)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-linters-16" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using linters (#16)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#data-types" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Data Types
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Data Types">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-confusion-with-octal-literals-17" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating confusion with octal literals (#17)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#neglecting-integer-overflows-18" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Neglecting integer overflows (#18)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-floating-points-19" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding floating-points (#19)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-slice-length-and-capacity-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding slice length and capacity (#20)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inefficient-slice-initialization-21" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inefficient slice initialization (#21)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-confused-about-nil-vs-empty-slice-22" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being confused about nil vs. empty slice (#22)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-properly-checking-if-a-slice-is-empty-23" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not properly checking if a slice is empty (#23)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-making-slice-copies-correctly-24" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not making slice copies correctly (#24)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unexpected-side-effects-using-slice-append-25" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unexpected side effects using slice append (#25)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#slices-and-memory-leaks-26" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Slices and memory leaks (#26)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Slices and memory leaks (#26)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#leaking-capacity" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Leaking capacity
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#slice-and-pointers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Slice and pointers
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inefficient-map-initialization-27" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inefficient map initialization (#27)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#maps-and-memory-leaks-28" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Maps and memory leaks (#28)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-values-incorrectly-29" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing values incorrectly (#29)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#control-structures" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Control Structures
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Control Structures">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-that-elements-are-copied-in-range-loops-30" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring that elements are copied in range loops (#30)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-arguments-are-evaluated-in-range-loops-channels-and-arrays-31" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how arguments are evaluated in range loops (channels and arrays) (#31)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-the-impacts-of-using-pointer-elements-in-range-loops-32" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring the impacts of using pointer elements in range loops (#32)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration-33" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Making wrong assumptions during map iterations (ordering and map insert during iteration) (#33)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-the-break-statement-works-34" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how the break statement works (#34)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-defer-inside-a-loop-35" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using defer inside a loop (#35)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#strings" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Strings
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Strings">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-concept-of-rune-36" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the concept of rune (#36)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#inaccurate-string-iteration-37" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Inaccurate string iteration (#37)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-trim-functions-38" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing trim functions (#38)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#under-optimized-strings-concatenation-39" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Under-optimized strings concatenation (#39)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#useless-string-conversions-40" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Useless string conversions (#40)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#substring-and-memory-leaks-41" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Substring and memory leaks (#41)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#functions-and-methods" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Functions and Methods
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Functions and Methods">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-knowing-which-type-of-receiver-to-use-42" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not knowing which type of receiver to use (#42)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#never-using-named-result-parameters-43" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Never using named result parameters (#43)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unintended-side-effects-with-named-result-parameters-44" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Unintended side effects with named result parameters (#44)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#returning-a-nil-receiver-45" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Returning a nil receiver (#45)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-a-filename-as-a-function-input-46" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using a filename as a function input (#46)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-how-defer-arguments-and-receivers-are-evaluated-argument-evaluation-pointer-and-value-receivers-47" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring how defer arguments and receivers are evaluated (argument evaluation, pointer, and value receivers) (#47)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#error-management" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Error Management
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Error Management">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#panicking-48" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Panicking (#48)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ignoring-when-to-wrap-an-error-49" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Ignoring when to wrap an error (#49)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-an-error-type-inaccurately-50" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing an error type inaccurately (#50)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#comparing-an-error-value-inaccurately-51" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Comparing an error value inaccurately (#51)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#handling-an-error-twice-52" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Handling an error twice (#52)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-handling-an-error-53" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not handling an error (#53)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-handling-defer-errors-54" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not handling defer errors (#54)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concurrency-foundations" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Concurrency: Foundations
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Concurrency: Foundations">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#mixing-up-concurrency-and-parallelism-55" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Mixing up concurrency and parallelism (#55)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#thinking-concurrency-is-always-faster-56" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Thinking concurrency is always faster (#56)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-puzzled-about-when-to-use-channels-or-mutexes-57" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being puzzled about when to use channels or mutexes (#57)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-race-problems-data-races-vs-race-conditions-and-the-go-memory-model-58" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding race problems (data races vs. race conditions and the Go memory model) (#58)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Not understanding race problems (data races vs. race conditions and the Go memory model) (#58)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#data-race" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Data Race
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#race-condition" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Race Condition
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-concurrency-impacts-of-a-workload-type-59" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the concurrency impacts of a workload type (#59)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misunderstanding-go-contexts-60" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misunderstanding Go contexts (#60)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Misunderstanding Go contexts (#60)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#deadline" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Deadline
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#cancellation-signals" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Cancellation signals
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#context-values" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Context values
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#catching-a-context-cancellation" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Catching a context cancellation
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concurrency-practice" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Concurrency: Practice
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Concurrency: Practice">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#propagating-an-inappropriate-context-61" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Propagating an inappropriate context (#61)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#starting-a-goroutine-without-knowing-when-to-stop-it-62" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Starting a goroutine without knowing when to stop it (#62)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-careful-with-goroutines-and-loop-variables-63" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being careful with goroutines and loop variables (#63)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#expecting-a-deterministic-behavior-using-select-and-channels-64" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Expecting a deterministic behavior using select and channels (#64)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-notification-channels-65" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using notification channels (#65)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-nil-channels-66" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using nil channels (#66)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#being-puzzled-about-channel-size-67" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Being puzzled about channel size (#67)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-about-possible-side-effects-with-string-formatting-68" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting about possible side effects with string formatting (#68)
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Forgetting about possible side effects with string formatting (#68)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#etcd-data-race" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
etcd data race
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#deadlock" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Deadlock
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#creating-data-races-with-append-69" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Creating data races with append (#69)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-mutexes-inaccurately-with-slices-and-maps-70" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using mutexes inaccurately with slices and maps (#70)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#misusing-syncwaitgroup-71" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Misusing sync.WaitGroup (#71)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-about-synccond-72" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting about sync.Cond (#72)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-errgroup-73" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using errgroup (#73)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#copying-a-sync-type-74" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Copying a sync type (#74)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#standard-library" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Standard Library
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Standard Library">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#providing-a-wrong-time-duration-75" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Providing a wrong time duration (#75)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#timeafter-and-memory-leaks-76" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
time.After and memory leaks (#76)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#json-handling-common-mistakes-77" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
JSON handling common mistakes (#77)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#common-sql-mistakes-78" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Common SQL mistakes (#78)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-closing-transient-resources-http-body-sqlrows-and-osfile-79" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not closing transient resources (HTTP body, sql.Rows, and os.File) (#79)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#forgetting-the-return-statement-after-replying-to-an-http-request-80" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Forgetting the return statement after replying to an HTTP request (#80)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#using-the-default-http-client-and-server-81" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Using the default HTTP client and server (#81)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#testing" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Testing
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Testing">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-categorizing-tests-build-tags-environment-variables-and-short-mode-82" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not categorizing tests (build tags, environment variables, and short mode) (#82)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-enabling-the-race-flag-83" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not enabling the race flag (#83)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-test-execution-modes-parallel-and-shuffle-84" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using test execution modes (parallel and shuffle) (#84)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-table-driven-tests-85" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using table-driven tests (#85)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sleeping-in-unit-tests-86" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Sleeping in unit tests (#86)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-dealing-with-the-time-api-efficiently-87" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not dealing with the time API efficiently (#87)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-testing-utility-packages-httptest-and-iotest-88" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using testing utility packages (httptest and iotest) (#88)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#writing-inaccurate-benchmarks-89" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Writing inaccurate benchmarks (#89)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-exploring-all-the-go-testing-features-90" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not exploring all the Go testing features (#90)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-fuzzing-community-mistake" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using fuzzing (community mistake)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optimizations" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Optimizations
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="Optimizations">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-cpu-caches-91" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding CPU caches (#91)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#writing-concurrent-code-that-leads-to-false-sharing-92" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Writing concurrent code that leads to false sharing (#92)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-taking-into-account-instruction-level-parallelism-93" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not taking into account instruction-level parallelism (#93)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-being-aware-of-data-alignment-94" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not being aware of data alignment (#94)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-stack-vs-heap-95" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding stack vs. heap (#95)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-knowing-how-to-reduce-allocations-api-change-compiler-optimizations-and-syncpool-96" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not knowing how to reduce allocations (API change, compiler optimizations, and sync.Pool) (#96)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-relying-on-inlining-97" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not relying on inlining (#97)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-using-go-diagnostics-tooling-98" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not using Go diagnostics tooling (#98)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-how-the-gc-works-99" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding how the GC works (#99)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes-100" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Not understanding the impacts of running Go in Docker and Kubernetes (#100)
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#community" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
Community
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-content" data-md-component="content">
|
||
<article class="md-content__inner md-typeset">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h1 id="common-go-mistakes">Common Go Mistakes</h1>
|
||
<details class="tip" open="open">
|
||
<summary>The Coder Cafe</summary>
|
||
<p>If you enjoyed my book, you may be interested in my latest project: <a href="https://thecoder.cafe">The Coder Cafe</a>, a daily newsletter for coders.</p>
|
||
<blockquote>
|
||
<p>Feeling overwhelmed by the endless stream of tech content? At The Coder Cafe, we serve one essential concept for coders daily. Written by a senior software engineer at Google, it's perfectly brewed for your morning coffee, helping you grow your skills deeply.</p>
|
||
</blockquote>
|
||
<p><center><a href="https://thecoder.cafe"><img src="../img/thecodercafe.png" alt="" style="width:480px;height:240px;"></a></center></p>
|
||
</details>
|
||
<p>This page is a summary of the mistakes in the <a href="book/">100 Go Mistakes and How to Avoid Them book</a>. Meanwhile, it's also open to the community. If you believe that a common Go mistake should be added, please create an <a href="https://github.com/teivah/100-go-mistakes/issues/new?assignees=&labels=community+mistake&template=community_mistake.md&title=">issue</a>.</p>
|
||
<p><a class="glightbox" href="img/inside-cover.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="" src="img/inside-cover.png" /></a></p>
|
||
<details class="warning" open="open">
|
||
<summary>Beta</summary>
|
||
<p>You're viewing a beta version enriched with significantly more content. However, this version is not yet complete, and I'm looking for volunteers to help me summarize the remaining mistakes (<a href="https://github.com/teivah/100-go-mistakes/issues/43">GitHub issue #43</a>).</p>
|
||
<p>Progress:
|
||
<progress value="81" max="100"/></p>
|
||
</details>
|
||
<h2 id="code-and-project-organization">Code and Project Organization</h2>
|
||
<h3 id="unintended-variable-shadowing-1">Unintended variable shadowing (#1)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Avoiding shadowed variables can help prevent mistakes like referencing the wrong variable or confusing readers.</p>
|
||
</details>
|
||
<p>Variable shadowing occurs when a variable name is redeclared in an inner block, but this practice is prone to mistakes. Imposing a rule to forbid shadowed variables depends on personal taste. For example, sometimes it can be convenient to reuse an existing variable name like <code>err</code> for errors. Yet, in general, we should remain cautious because we now know that we can face a scenario where the code compiles, but the variable that receives the value is not the one expected.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/1-variable-shadowing/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="unnecessary-nested-code-2">Unnecessary nested code (#2)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Avoiding nested levels and keeping the happy path aligned on the left makes building a mental code model easier.</p>
|
||
</details>
|
||
<p>In general, the more nested levels a function requires, the more complex it is to read and understand. Let’s see some different applications of this rule to optimize our code for readability:</p>
|
||
<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>
|
||
<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>
|
||
<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>
|
||
<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>
|
||
<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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="misusing-init-functions-3">Misusing init functions (#3)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When initializing variables, remember that init functions have limited error handling and make state handling and testing more complex. In most cases, initializations should be handled as specific functions.</p>
|
||
</details>
|
||
<p>An init function is a function used to initialize the state of an application. It takes no arguments and returns no result (a <code>func()</code> function). When a package is initialized, all the constant and variable declarations in the package are evaluated. Then, the init functions are executed.</p>
|
||
<p>Init functions can lead to some issues:</p>
|
||
<ul>
|
||
<li>They can limit error management.</li>
|
||
<li>They can complicate how to implement tests (for example, an external dependency must be set up, which may not be necessary for the scope of unit tests).</li>
|
||
<li>If the initialization requires us to set a state, that has to be done through global variables.</li>
|
||
</ul>
|
||
<p>We should be cautious with init functions. They can be helpful in some situations, however, such as defining static configuration. Otherwise, and in most cases, we should handle initializations through ad hoc functions.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/3-init-functions/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="overusing-getters-and-setters-4">Overusing getters and setters (#4)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Forcing the use of getters and setters isn’t idiomatic in Go. Being pragmatic and finding the right balance between efficiency and blindly following certain idioms should be the way to go.</p>
|
||
</details>
|
||
<p>Data encapsulation refers to hiding the values or state of an object. Getters and setters are means to enable encapsulation by providing exported methods on top of unexported object fields.</p>
|
||
<p>In Go, there is no automatic support for getters and setters as we see in some languages. It is also considered neither mandatory nor idiomatic to use getters and setters to access struct fields. We shouldn’t overwhelm our code with getters and setters on structs if they don’t bring any value. We should be pragmatic and strive to find the right balance between efficiency and following idioms that are sometimes considered indisputable in other programming paradigms.</p>
|
||
<p>Remember that Go is a unique language designed for many characteristics, including simplicity. However, if we find a need for getters and setters or, as mentioned, foresee a future need while guaranteeing forward compatibility, there’s nothing wrong with using them.</p>
|
||
<h3 id="interface-pollution-5">Interface pollution (#5)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Abstractions should be discovered, not created. To prevent unnecessary complexity, create an interface when you need it and not when you foresee needing it, or if you can at least prove the abstraction to be a valid one.</p>
|
||
</details>
|
||
<p>Read the full section <a href="5-interface-pollution/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/5-interface-pollution/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="interface-on-the-producer-side-6">Interface on the producer side (#6)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Keeping interfaces on the client side avoids unnecessary abstractions.</p>
|
||
</details>
|
||
<p>Interfaces are satisfied implicitly in Go, which tends to be a gamechanger compared to languages with an explicit implementation. In most cases, the approach to follow is similar to what we described in the previous section: <em>abstractions should be discovered, not created</em>. This means that it’s not up to the producer to force a given abstraction for all the clients. Instead, it’s up to the client to decide whether it needs some form of abstraction and then determine the best abstraction level for its needs.</p>
|
||
<p>An interface should live on the consumer side in most cases. However, in particular contexts (for example, when we know—not foresee—that an abstraction will be helpful for consumers), we may want to have it on the producer side. If we do, we should strive to keep it as minimal as possible, increasing its reusability potential and making it more easily composable.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/6-interface-producer/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="returning-interfaces-7">Returning interfaces (#7)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To prevent being restricted in terms of flexibility, a function shouldn’t return interfaces but concrete implementations in most cases. Conversely, a function should accept interfaces whenever possible.</p>
|
||
</details>
|
||
<p>In most cases, we shouldn’t return interfaces but concrete implementations. Otherwise, it can make our design more complex due to package dependencies and can restrict flexibility because all the clients would have to rely on the same abstraction. Again, the conclusion is similar to the previous sections: if we know (not foresee) that an abstraction will be helpful for clients, we can consider returning an interface. Otherwise, we shouldn’t force abstractions; they should be discovered by clients. If a client needs to abstract an implementation for whatever reason, it can still do that on the client’s side.</p>
|
||
<h3 id="any-says-nothing-8"><code>any</code> says nothing (#8)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Only use <code>any</code> if you need to accept or return any possible type, such as <code>json.Marshal</code>. Otherwise, <code>any</code> doesn’t provide meaningful information and can lead to compile-time issues by allowing a caller to call methods with any data type.</p>
|
||
</details>
|
||
<p>The <code>any</code> type can be helpful if there is a genuine need for accepting or returning any possible type (for instance, when it comes to marshaling or formatting). In general, we should avoid overgeneralizing the code we write at all costs. Perhaps a little bit of duplicated code might occasionally be better if it improves other aspects such as code expressiveness.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/8-any/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="being-confused-about-when-to-use-generics-9">Being confused about when to use generics (#9)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Relying on generics and type parameters can prevent writing boilerplate code to factor out elements or behaviors. However, do not use type parameters prematurely, but only when you see a concrete need for them. Otherwise, they introduce unnecessary abstractions and complexity.</p>
|
||
</details>
|
||
<p>Read the full section <a href="9-generics/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/9-generics/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-being-aware-of-the-possible-problems-with-type-embedding-10">Not being aware of the possible problems with type embedding (#10)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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>
|
||
<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 <code>Bar</code> contains a <code>Baz</code> field, this field is
|
||
promoted to <code>Foo</code>. Therefore, <code>Baz</code> becomes available from <code>Foo</code>.</p>
|
||
<p>What can we say about type embedding? First, let’s note that it’s rarely a necessity, and it means that whatever the use case, we can probably solve it as well without type embedding. Type embedding is mainly used for convenience: in most cases, to promote behaviors.</p>
|
||
<p>If we decide to use type embedding, we need to keep two main constraints in mind:</p>
|
||
<ul>
|
||
<li>It shouldn’t be used solely as some syntactic sugar to simplify accessing a field (such as <code>Foo.Baz()</code> instead of <code>Foo.Bar.Baz()</code>). If this is the only rationale, let’s not embed the inner type and use a field instead.</li>
|
||
<li>It shouldn’t promote data (fields) or a behavior (methods) we want to hide from the outside: for example, if it allows clients to access a locking behavior that should remain private to the struct.</li>
|
||
</ul>
|
||
<p>Using type embedding consciously by keeping these constraints in mind can help avoid boilerplate code with additional forwarding methods. However, let’s make sure we don’t do it solely for cosmetics and not promote elements that should remain hidden.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/10-type-embedding/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-using-the-functional-options-pattern-11">Not using the functional options pattern (#11)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To handle options conveniently and in an API-friendly manner, use the functional options pattern.</p>
|
||
</details>
|
||
<p>Although there are different implementations with minor variations, the main idea is as follows:</p>
|
||
<ul>
|
||
<li>An unexported struct holds the configuration: options.</li>
|
||
<li>Each option is a function that returns the same type: <code>type Option func(options *options) error</code>. 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.</li>
|
||
</ul>
|
||
<p><a class="glightbox" href="img/options.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="" src="img/options.png" /></a></p>
|
||
<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><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><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><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><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/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="project-misorganization-project-structure-and-package-organization-12">Project misorganization (project structure and package organization) (#12)</h3>
|
||
<p>Regarding the overall organization, there are different schools of thought. For example, should we organize our application by context or by layer? It depends on our preferences. We may favor grouping code per context (such as the customer context, the contract context, etc.), or we may favor following hexagonal architecture principles and group per technical layer. If the decision we make fits our use case, it cannot be a wrong decision, as long as we remain consistent with it.</p>
|
||
<p>Regarding packages, there are multiple best practices that we should follow. First, we should avoid premature packaging because it might cause us to overcomplicate a project. Sometimes, it’s better to use a simple organization and have our project evolve when we understand what it contains rather than forcing ourselves to make the perfect structure up front.
|
||
Granularity is another essential thing to consider. We should avoid having dozens of nano packages containing only one or two files. If we do, it’s because we have probably missed some logical connections across these packages, making our project harder for readers to understand. Conversely, we should also avoid huge packages that dilute the meaning of a package name.</p>
|
||
<p>Package naming should also be considered with care. As we all know (as developers), naming is hard. To help clients understand a Go project, we should name our packages after what they provide, not what they contain. Also, naming should be meaningful. Therefore, a package name should be short, concise, expressive, and, by convention, a single lowercase word.</p>
|
||
<p>Regarding what to export, the rule is pretty straightforward. We should minimize what should be exported as much as possible to reduce the coupling between packages and keep unnecessary exported elements hidden. If we are unsure whether to export an element or not, we should default to not exporting it. Later, if we discover that we need to export it, we can adjust our code. Let’s also keep in mind some exceptions, such as making fields exported so that a struct can be unmarshaled with encoding/json.</p>
|
||
<p>Organizing a project isn’t straightforward, but following these rules should help make it easier to maintain. However, remember that consistency is also vital to ease maintainability. Therefore, let’s make sure that we keep things as consistent as possible within a codebase.</p>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p>In 2023, the Go team has published an official guideline for organizing / structuring a Go project: <a href="https://go.dev/doc/modules/layout">go.dev/doc/modules/layout</a></p>
|
||
</details>
|
||
<h3 id="creating-utility-packages-13">Creating utility packages (#13)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Naming is a critical piece of application design. Creating packages such as <code>common</code>, <code>util</code>, and <code>shared</code> doesn’t bring much value for the reader. Refactor such packages into meaningful and specific package names.</p>
|
||
</details>
|
||
<p>Also, bear in mind that naming a package after what it provides and not what it contains can be an efficient way to increase its expressiveness.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/02-code-project-organization/13-utility-packages/stringset.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="ignoring-package-name-collisions-14">Ignoring package name collisions (#14)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To avoid naming collisions between variables and packages, leading to confusion or perhaps even bugs, use unique names for each one. If this isn’t feasible, use an import alias to change the qualifier to differentiate the package name from the variable name, or think of a better name.</p>
|
||
</details>
|
||
<p>Package collisions occur when a variable name collides with an existing package name, preventing the package from being reused. We should prevent variable name collisions to avoid ambiguity. If we face a collision, we should either find another meaningful name or use an import alias.</p>
|
||
<h3 id="missing-code-documentation-15">Missing code documentation (#15)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To help clients and maintainers understand your code’s purpose, document exported elements.</p>
|
||
</details>
|
||
<p>Documentation is an important aspect of coding. It simplifies how clients can consume an API but can also help in maintaining a project. In Go, we should follow some rules to make our code idiomatic:</p>
|
||
<p>First, every exported element must be documented. Whether it is a structure, an interface, a function, or something else, if it’s exported, it must be documented. The convention is to add comments, starting with the name of the exported element.</p>
|
||
<p>As a convention, each comment should be a complete sentence that ends with punctuation. Also bear in mind that when we document a function (or a method), we should highlight what the function intends to do, not how it does it; this belongs to the core of a function and comments, not documentation. Furthermore, the documentation should ideally provide enough information that the consumer does not have to look at our code to understand how to use an exported element.</p>
|
||
<p>When it comes to documenting a variable or a constant, we might be interested in conveying two aspects: its purpose and its content. The former should live as code documentation to be useful for external clients. The latter, though, shouldn’t necessarily be public.</p>
|
||
<p>To help clients and maintainers understand a package’s scope, we should also document each package. The convention is to start the comment with <code>// Package</code> followed by the package name. The first line of a package comment should be concise. That’s because it will appear in the package. Then, we can provide all the information we need in the following lines.</p>
|
||
<p>Documenting our code shouldn’t be a constraint. We should take the opportunity to make sure it helps clients and maintainers to understand the purpose of our code.</p>
|
||
<h3 id="not-using-linters-16">Not using linters (#16)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To improve code quality and consistency, use linters and formatters.</p>
|
||
</details>
|
||
<p>A linter is an automatic tool to analyze code and catch errors. The scope of this section isn’t to give an exhaustive list of the existing linters; otherwise, it will become deprecated pretty quickly. But we should understand and remember why linters are essential for most Go projects.</p>
|
||
<p>However, if you’re not a regular user of linters, here is a list that you may want to use daily:</p>
|
||
<ul>
|
||
<li><a href="https://golang.org/cmd/vet">https://golang.org/cmd/vet</a>—A standard Go analyzer</li>
|
||
<li><a href="https://github.com/kisielk/errcheck">https://github.com/kisielk/errcheck</a>—An error checker</li>
|
||
<li><a href="https://github.com/fzipp/gocyclo">https://github.com/fzipp/gocyclo</a>—A cyclomatic complexity analyzer</li>
|
||
<li><a href="https://github.com/jgautheron/goconst">https://github.com/jgautheron/goconst</a>—A repeated string constants analyzer</li>
|
||
</ul>
|
||
<p>Besides linters, we should also use code formatters to fix code style. Here is a list of some code formatters for you to try:</p>
|
||
<ul>
|
||
<li><a href="https://golang.org/cmd/gofmt">https://golang.org/cmd/gofmt</a>—A standard Go code formatter</li>
|
||
<li><a href="https://godoc.org/golang.org/x/tools/cmd/goimports">https://godoc.org/golang.org/x/tools/cmd/goimports</a>—A standard Go imports formatter</li>
|
||
</ul>
|
||
<p>Meanwhile, we should also look at golangci-lint (<a href="https://github.com/golangci/golangci-lint">https://github.com/golangci/golangci-lint</a>). It’s a linting tool that provides a facade on top of many useful linters and formatters. Also, it allows running the linters in parallel to improve analysis speed, which is quite handy.</p>
|
||
<p>Linters and formatters are a powerful way to improve the quality and consistency of our codebase. Let’s take the time to understand which one we should use and make sure we automate their execution (such as a CI or Git precommit hook).</p>
|
||
<h2 id="data-types">Data Types</h2>
|
||
<h3 id="creating-confusion-with-octal-literals-17">Creating confusion with octal literals (#17)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When reading existing code, bear in mind that integer literals starting with <code>0</code> are octal numbers. Also, to improve readability, make octal integers explicit by prefixing them with <code>0o</code>.</p>
|
||
</details>
|
||
<p>Octal numbers start with a 0 (e.g., <code>010</code> is equal to 8 in base 10). To improve readability and avoid potential mistakes for future code readers, we should make octal numbers explicit using the <code>0o</code> prefix (e.g., <code>0o10</code>).</p>
|
||
<p>We should also note the other integer literal representations:</p>
|
||
<ul>
|
||
<li><em>Binary</em>—Uses a <code>0b</code> or <code>0B</code> prefix (for example, <code>0b100</code> is equal to 4 in base 10)</li>
|
||
<li><em>Hexadecimal</em>—Uses an <code>0x</code> or <code>0X</code> prefix (for example, <code>0xF</code> is equal to 15 in base 10)</li>
|
||
<li><em>Imaginary</em>—Uses an <code>i</code> suffix (for example, <code>3i</code>)</li>
|
||
</ul>
|
||
<p>We can also use an underscore character (_) as a separator for readability. For example, we can write 1 billion this way: <code>1_000_000_000</code>. We can also use the underscore character with other representations (for example, <code>0b00_00_01</code>).</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/17-octal-literals/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="neglecting-integer-overflows-18">Neglecting integer overflows (#18)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Because integer overflows and underflows are handled silently in Go, you can implement your own functions to catch them.</p>
|
||
</details>
|
||
<p>In Go, an integer overflow that can be detected at compile time generates a compilation error. For example,</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="kt">int32</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">MaxInt32</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span>
|
||
</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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-understanding-floating-points-19">Not understanding floating-points (#19)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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>
|
||
<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:</p>
|
||
<ul>
|
||
<li>When comparing two floating-point numbers, check that their difference is within an acceptable range.</li>
|
||
<li>When performing additions or subtractions, group operations with a similar order of magnitude for better accuracy.</li>
|
||
<li>To favor accuracy, if a sequence of operations requires addition, subtraction, multiplication, or division, perform the multiplication and division operations first.</li>
|
||
</ul>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/19-floating-points/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-understanding-slice-length-and-capacity-20">Not understanding slice length and capacity (#20)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding the difference between slice length and capacity should be part of a Go developer’s core knowledge. The slice length is the number of available elements in the slice, whereas the slice capacity is the number of elements in the backing array.</p>
|
||
</details>
|
||
<p>Read the full section <a href="20-slice/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/20-slice-length-cap/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="inefficient-slice-initialization-21">Inefficient slice initialization (#21)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When creating a slice, initialize it with a given length or capacity if its length is already known. This reduces the number of allocations and improves performance.</p>
|
||
</details>
|
||
<p>While initializing a slice using <code>make</code>, we can provide a length and an optional capacity. Forgetting to pass an appropriate value for both of these parameters when it makes sense is a widespread mistake. Indeed, it can lead to multiple copies and additional effort for the <abbr title="Garbage Collector">GC</abbr> to clean the temporary backing arrays. Performance-wise, there’s no good reason not to give the Go runtime a helping hand.</p>
|
||
<p>Our options are to allocate a slice with either a given capacity or a given length. Of these two solutions, we have seen that the second tends to be slightly faster. But using a given capacity and append can be easier to implement and read in some contexts.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/21-slice-init/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="being-confused-about-nil-vs-empty-slice-22">Being confused about nil vs. empty slice (#22)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To prevent common confusions such as when using the <code>encoding/json</code> or the <code>reflect</code> package, you need to understand the difference between nil and empty slices. Both are zero-length, zero-capacity slices, but only a nil slice doesn’t require allocation.</p>
|
||
</details>
|
||
<p>In Go, there is a distinction between nil and empty slices. A nil slice is equals to <code>nil</code>, whereas an empty slice has a length of zero. A nil slice is empty, but an empty slice isn’t necessarily <code>nil</code>. Meanwhile, a nil slice doesn’t require any allocation. We have seen throughout this section how to initialize a slice depending on the context by using</p>
|
||
<ul>
|
||
<li><code>var s []string</code> if we aren’t sure about the final length and the slice can be empty</li>
|
||
<li><code>[]string(nil)</code> as syntactic sugar to create a nil and empty slice</li>
|
||
<li><code>make([]string, length)</code> if the future length is known</li>
|
||
</ul>
|
||
<p>The last option, <code>[]string{}</code>, should be avoided if we initialize the slice without elements. Finally, let’s check whether the libraries we use make the distinctions between nil and empty slices to prevent unexpected behaviors.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/22-nil-empty-slice/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-properly-checking-if-a-slice-is-empty-23">Not properly checking if a slice is empty (#23)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To check if a slice doesn’t contain any element, check its length. This check works regardless of whether the slice is <code>nil</code> or empty. The same goes for maps. To design unambiguous APIs, you shouldn’t distinguish between nil and empty slices.</p>
|
||
</details>
|
||
<p>To determine whether a slice has elements, we can either do it by checking if the slice is nil or if its length is equal to 0. Checking the length is the best option to follow as it will cover both if the slice is empty or if the slice is nil.</p>
|
||
<p>Meanwhile, when designing interfaces, we should avoid distinguishing nil and empty slices, which leads to subtle programming errors. When returning slices, it should make neither a semantic nor a technical difference if we return a nil or empty slice. Both should mean the same thing for the callers. This principle is the same with maps. To check if a map is empty, check its length, not whether it’s nil.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/23-checking-slice-empty/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-making-slice-copies-correctly-24">Not making slice copies correctly (#24)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To copy one slice to another using the <code>copy</code> built-in function, remember that the number of copied elements corresponds to the minimum between the two slice’s lengths.</p>
|
||
</details>
|
||
<p>Copying elements from one slice to another is a reasonably frequent operation. When using copy, we must recall that the number of elements copied to the destination corresponds to the minimum between the two slices’ lengths. Also bear in mind that other alternatives exist to copy a slice, so we shouldn’t be surprised if we find them in a codebase.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/24-slice-copy/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="unexpected-side-effects-using-slice-append-25">Unexpected side effects using slice append (#25)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Using copy or the full slice expression is a way to prevent <code>append</code> from creating conflicts if two different functions use slices backed by the same array. However, only a slice copy prevents memory leaks if you want to shrink a large slice.</p>
|
||
</details>
|
||
<p>When using slicing, we must remember that we can face a situation leading to unintended side effects. If the resulting slice has a length smaller than its capacity, append can mutate the original slice. If we want to restrict the range of possible side effects, we can use either a slice copy or the full slice expression, which prevents us from doing a copy.</p>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p><code>s[low:high:max]</code> (full slice expression): This statement creates a slice similar to the one created with <code>s[low:high]</code>, except that the resulting slice’s capacity is equal to <code>max - low</code>.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/25-slice-append/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="slices-and-memory-leaks-26">Slices and memory leaks (#26)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Working with a slice of pointers or structs with pointer fields, you can avoid memory leaks by marking as nil the elements excluded by a slicing operation.</p>
|
||
</details>
|
||
<h4 id="leaking-capacity">Leaking capacity</h4>
|
||
<p>Remember that slicing a large slice or array can lead to potential high memory consumption. The remaining space won’t be reclaimed by the <abbr title="Garbage Collector">GC</abbr>, and we can keep a large backing array despite using only a few elements. Using a slice copy is the solution to prevent such a case.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/26-slice-memory-leak/capacity-leak"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h4 id="slice-and-pointers">Slice and pointers</h4>
|
||
<p>When we use the slicing operation with pointers or structs with pointer fields, we need to know that the <abbr title="Garbage Collector">GC</abbr> won’t reclaim these elements. In that case, the two options are to either perform a copy or explicitly mark the remaining elements or their fields to <code>nil</code>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/26-slice-memory-leak/slice-pointers"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="inefficient-map-initialization-27">Inefficient map initialization (#27)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When creating a map, initialize it with a given length if its length is already known. This reduces the number of allocations and improves performance.</p>
|
||
</details>
|
||
<p>A map provides an unordered collection of key-value pairs in which all the keys are distinct. In Go, a map is based on the hash table data structure. Internally, a hash table is an array of buckets, and each bucket is a pointer to an array of key-value pairs.</p>
|
||
<p>If we know up front the number of elements a map will contain, we should create it by providing an initial size. Doing this avoids potential map growth, which is quite heavy computation-wise because it requires reallocating enough space and rebalancing all the elements.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/27-map-init/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="maps-and-memory-leaks-28">Maps and memory leaks (#28)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>A map can always grow in memory, but it never shrinks. Hence, if it leads to some memory issues, you can try different options, such as forcing Go to recreate the map or using pointers.</p>
|
||
</details>
|
||
<p>Read the full section <a href="28-maps-memory-leaks/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/28-map-memory-leak/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="comparing-values-incorrectly-29">Comparing values incorrectly (#29)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To compare types in Go, you can use the == and != operators if two types are comparable: Booleans, numerals, strings, pointers, channels, and structs are composed entirely of comparable types. Otherwise, you can either use <code>reflect.DeepEqual</code> and pay the price of reflection or use custom implementations and libraries.</p>
|
||
</details>
|
||
<p>It’s essential to understand how to use <code>==</code> and <code>!=</code> to make comparisons effectively. We can use these operators on operands that are comparable:</p>
|
||
<ul>
|
||
<li><em>Booleans</em>—Compare whether two Booleans are equal.</li>
|
||
<li><em>Numerics (int, float, and complex types)</em>—Compare whether two numerics are equal.</li>
|
||
<li><em>Strings</em>—Compare whether two strings are equal.</li>
|
||
<li><em>Channels</em>—Compare whether two channels were created by the same call to make or if both are nil.</li>
|
||
<li><em>Interfaces</em>—Compare whether two interfaces have identical dynamic types and equal dynamic values or if both are nil.</li>
|
||
<li><em>Pointers</em>—Compare whether two pointers point to the same value in memory or if both are nil.</li>
|
||
<li><em>Structs and arrays</em>—Compare whether they are composed of similar types.</li>
|
||
</ul>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p>We can also use the <code>?</code>, <code>>=</code>, <code><</code>, and <code>></code> operators with numeric types to compare values and with strings to compare their lexical order.</p>
|
||
</details>
|
||
<p>If operands are not comparable (e.g., slices and maps), we have to use other options such as reflection. Reflection is a form of metaprogramming, and it refers to the ability of an application to introspect and modify its structure and behavior. For example, in Go, we can use <code>reflect.DeepEqual</code>. This function reports whether two elements are deeply equal by recursively traversing two values. The elements it accepts are basic types plus arrays, structs, slices, maps, pointers, interfaces, and functions. Yet, the main catch is the performance penalty.</p>
|
||
<p>If performance is crucial at run time, implementing our custom method might be the best solution.
|
||
One additional note: we must remember that the standard library has some existing comparison methods. For example, we can use the optimized <code>bytes.Compare</code> function to compare two slices of bytes. Before implementing a custom method, we need to make sure we don’t reinvent the wheel.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/03-data-types/29-comparing-values/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="control-structures">Control Structures</h2>
|
||
<h3 id="ignoring-that-elements-are-copied-in-range-loops-30">Ignoring that elements are copied in <code>range</code> loops (#30)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>The value element in a <code>range</code> loop is a copy. Therefore, to mutate a struct, for example, access it via its index or via a classic <code>for</code> loop (unless the element or the field you want to modify is a pointer).</p>
|
||
</details>
|
||
<p>A range loop allows iterating over different data structures:</p>
|
||
<ul>
|
||
<li>String</li>
|
||
<li>Array</li>
|
||
<li>Pointer to an array</li>
|
||
<li>Slice</li>
|
||
<li>Map</li>
|
||
<li>Receiving channel</li>
|
||
</ul>
|
||
<p>Compared to a classic for <code>loop</code>, a <code>range</code> loop is a convenient way to iterate over all the elements of one of these data structures, thanks to its concise syntax.</p>
|
||
<p>Yet, we should remember that the value element in a range loop is a copy. Therefore, if the value is a struct we need to mutate, we will only update the copy, not the element itself, unless the value or field we modify is a pointer. The favored options are to access the element via the index using a range loop or a classic for loop.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/30-range-loop-element-copied/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<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>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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>
|
||
<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/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="ignoring-the-impacts-of-using-pointer-elements-in-range-loops-32"><img alt="⚠" class="twemoji" src="https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.0.3/assets/svg/26a0.svg" title=":warning:" /> Ignoring the impacts of using pointer elements in <code>range</code> loops (#32)</h3>
|
||
<details class="warning" open="open">
|
||
<summary>Warning</summary>
|
||
<p>This mistake isn't relevant anymore from Go 1.22 (<a href="https://go.dev/blog/loopvar-preview">details</a>).</p>
|
||
</details>
|
||
<h3 id="making-wrong-assumptions-during-map-iterations-ordering-and-map-insert-during-iteration-33">Making wrong assumptions during map iterations (ordering and map insert during iteration) (#33)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To ensure predictable outputs when using maps, remember that a map data structure:</p>
|
||
</details>
|
||
<ul>
|
||
<li>Doesn’t order the data by keys</li>
|
||
<li>Doesn’t preserve the insertion order</li>
|
||
<li>Doesn’t have a deterministic iteration order</li>
|
||
<li>Doesn’t guarantee that an element added during an iteration will be produced during this iteration</li>
|
||
</ul>
|
||
<!-- TODO -->
|
||
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/04-control-structures/33-map-iteration/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="ignoring-how-the-break-statement-works-34">Ignoring how the <code>break</code> statement works (#34)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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>
|
||
<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 execution 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>
|
||
<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="hll"><span class="nx">loop</span><span class="p">:</span>
|
||
</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="hll"><span class="w"> </span><span class="k">break</span><span class="w"> </span><span class="nx">loop</span>
|
||
</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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="using-defer-inside-a-loop-35">Using <code>defer</code> inside a loop (#35)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Extracting loop logic inside a function leads to executing a <code>defer</code> statement at the end of each iteration.</p>
|
||
</details>
|
||
<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>
|
||
<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>
|
||
<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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="strings">Strings</h2>
|
||
<h3 id="not-understanding-the-concept-of-rune-36">Not understanding the concept of rune (#36)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding that a rune corresponds to the concept of a Unicode code point and that it can be composed of multiple bytes should be part of the Go developer’s core knowledge to work accurately with strings.</p>
|
||
</details>
|
||
<p>As runes are everywhere in Go, it's important to understand the following:</p>
|
||
<ul>
|
||
<li>A charset is a set of characters, whereas an encoding describes how to translate a charset into binary.</li>
|
||
<li>In Go, a string references an immutable slice of arbitrary bytes.</li>
|
||
<li>Go source code is encoded using UTF-8. Hence, all string literals are UTF-8 strings. But because a string can contain arbitrary bytes, if it’s obtained from somewhere else (not the source code), it isn’t guaranteed to be based on the UTF-8 encoding.</li>
|
||
<li>A <code>rune</code> corresponds to the concept of a Unicode code point, meaning an item represented by a single value.</li>
|
||
<li>Using UTF-8, a Unicode code point can be encoded into 1 to 4 bytes.</li>
|
||
<li>Using <code>len()</code> on a string in Go returns the number of bytes, not the number of runes.</li>
|
||
</ul>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/36-rune/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="inaccurate-string-iteration-37">Inaccurate string iteration (#37)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<p>Iterating on a string is a common operation for developers. Perhaps we want to perform 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>
|
||
<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>
|
||
<li>We jumped from position 1 to position 3: what is at position 2?</li>
|
||
<li>len returns a count of 6, whereas s contains only 5 runes.</li>
|
||
</ul>
|
||
<p>Let’s start with the last observation. We already mentioned that len returns the number of bytes in a string, not the number of runes. Because we assigned a string literal to <code>s</code>, <code>s</code> is a UTF-8 string. Meanwhile, the special character "ê" isn’t encoded in a single byte; it requires 2 bytes. Therefore, calling <code>len(s)</code> returns 6.</p>
|
||
<p>Meanwhile, in the previous example, we have to understand that we don't iterate over each rune; instead, we iterate over each starting index of a rune:</p>
|
||
<p><a class="glightbox" href="img/rune.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="" src="img/rune.png" /></a></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>
|
||
<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>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-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-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="hll"><span class="nx">runes</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="nb">rune</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span>
|
||
</span></span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></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">runes</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></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-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="p">}</span>
|
||
</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>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-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-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a><span class="nx">r</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="nb">rune</span><span class="p">(</span><span class="nx">s</span><span class="p">)[</span><span class="mi">4</span><span class="p">]</span>
|
||
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%c\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="p">)</span><span class="w"> </span><span class="c1">// o</span>
|
||
</span></code></pre></div>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/37-string-iteration/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="misusing-trim-functions-38">Misusing trim functions (#38)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p><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>
|
||
</details>
|
||
<p>For example:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">strings</span><span class="p">.</span><span class="nx">TrimRight</span><span class="p">(</span><span class="s">"123oxo"</span><span class="p">,</span><span class="w"> </span><span class="s">"xo"</span><span class="p">))</span>
|
||
</span></code></pre></div>
|
||
<p>The example prints 123:</p>
|
||
<p><a class="glightbox" href="img/trim.png" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img alt="" src="img/trim.png" /></a></p>
|
||
<p>Conversely, <code>strings.TrimLeft</code> removes all the leading runes contained in a set.</p>
|
||
<p>On the other side, <code>strings.TrimSuffix</code> / <code>strings.TrimPrefix</code> returns a string without the provided trailing suffix / prefix.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/38-trim/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="under-optimized-strings-concatenation-39">Under-optimized strings concatenation (#39)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Concatenating a list of strings should be done with <code>strings.Builder</code> to prevent allocating a new string during each iteration.</p>
|
||
</details>
|
||
<p>Let’s consider a <code>concat</code> function that concatenates all the string elements of a slice using the <code>+=</code> operator:</p>
|
||
<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>
|
||
<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="hll"><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><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="hll"><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><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>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p><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> implements 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>
|
||
</details>
|
||
<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>
|
||
<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 preallocation). The input slice contains 1,000 strings, and each string contains 1,000 bytes:</p>
|
||
<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 concatenate a few strings (such as a name and a surname), using <code>strings.Builder</code> is not recommended 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/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="useless-string-conversions-40">Useless string conversions (#40)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Remembering that the <code>bytes</code> package offers the same operations as the <code>strings</code> package can help avoid extra byte/string conversions.</p>
|
||
</details>
|
||
<p>When choosing to work with a string or a <code>[]byte</code>, most programmers tend to favor strings for convenience. But most I/O is actually done with <code>[]byte</code>. For example, <code>io.Reader</code>, <code>io.Writer</code>, and <code>io.ReadAll</code> work with <code>[]byte</code>, not strings.</p>
|
||
<p>When we’re wondering whether we should work with strings or <code>[]byte</code>, let’s recall that working with <code>[]byte</code> isn’t necessarily less convenient. Indeed, all the exported functions of the strings package also have alternatives in the <code>bytes</code> package: <code>Split</code>, <code>Count</code>, <code>Contains</code>, <code>Index</code>, and so on. Hence, whether we’re doing I/O or not, we should first check whether we could implement a whole workflow using bytes instead of strings and avoid the price of additional conversions.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/40-string-conversion/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="substring-and-memory-leaks-41">Substring and memory leaks (#41)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Using copies instead of substrings can prevent memory leaks, as the string returned by a substring operation will be backed by the same byte array.</p>
|
||
</details>
|
||
<p>In mistake <a href="#slice-and-memory-leaks--26-">#26, “Slices and memory leaks,”</a> we saw how slicing a slice or array may lead to memory leak situations. This principle also applies to string and substring operations.</p>
|
||
<p>We need to keep two things in mind while using the substring operation in Go. First, the interval provided is based on the number of bytes, not the number of runes. Second, a substring operation may lead to a memory leak as the resulting substring will share the same backing array as the initial string. The solutions to prevent this case from happening are to perform a string copy manually or to use <code>strings.Clone</code> from Go 1.18.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/05-strings/41-substring-memory-leak/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="functions-and-methods">Functions and Methods</h2>
|
||
<h3 id="not-knowing-which-type-of-receiver-to-use-42">Not knowing which type of receiver to use (#42)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>The decision whether to use a value or a pointer receiver should be made based on factors such as the type, whether it has to be mutated, whether it contains a field that can’t be copied, and how large the object is. When in doubt, use a pointer receiver.</p>
|
||
</details>
|
||
<p>Choosing between value and pointer receivers isn’t always straightforward. Let’s discuss some of the conditions to help us choose.</p>
|
||
<p>A receiver <em>must</em> be a pointer</p>
|
||
<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>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><span class="kd">type</span><span class="w"> </span><span class="nx">slice</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span>
|
||
</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><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">*</span><span class="nx">slice</span><span class="p">)</span><span class="w"> </span><span class="nx">add</span><span class="p">(</span><span class="nx">element</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-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a><span class="w"> </span><span class="o">*</span><span class="nx">s</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="o">*</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="nx">element</span><span class="p">)</span>
|
||
</span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a><span class="p">}</span>
|
||
</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>
|
||
<p>A receiver <em>should</em> be a pointer</p>
|
||
<ul>
|
||
<li>If the receiver is a large object. Using a pointer can make the call more efficient, as doing so prevents making an extensive copy. When in doubt about how large is large, benchmarking can be the solution; it’s pretty much impossible to state a specific size, because it depends on many factors.</li>
|
||
</ul>
|
||
<p>A receiver <em>must</em> be a value</p>
|
||
<ul>
|
||
<li>If we have to enforce a receiver’s immutability.</li>
|
||
<li>If the receiver is a map, function, or channel. Otherwise, a compilation error
|
||
occurs.</li>
|
||
</ul>
|
||
<p>A receiver <em>should</em> be a value</p>
|
||
<ul>
|
||
<li>If the receiver is a slice that doesn’t have to be mutated.</li>
|
||
<li>If the receiver is a small array or struct that is naturally a value type without mutable fields, such as <code>time.Time</code>.</li>
|
||
<li>If the receiver is a basic type such as <code>int</code>, <code>float64</code>, or <code>string</code>.</li>
|
||
</ul>
|
||
<p>Of course, it’s impossible to be exhaustive, as there will always be edge cases, but this section’s goal was to provide guidance to cover most cases. By default, we can choose to go with a value receiver unless there’s a good reason not to do so. In doubt, we should use a pointer receiver.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/42-receiver/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="never-using-named-result-parameters-43">Never using named result parameters (#43)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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 arguments). 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>
|
||
<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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="unintended-side-effects-with-named-result-parameters-44">Unintended side effects with named result parameters (#44)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>See <a href="#never-using-named-result-parameters-43">#43</a>.</p>
|
||
</details>
|
||
<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>
|
||
<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 initialized 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 cautious 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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="returning-a-nil-receiver-45">Returning a nil receiver (#45)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When returning an interface, be cautious about not returning a nil pointer but an explicit nil value. Otherwise, unintended consequences may occur and the caller will receive a non-nil value.</p>
|
||
</details>
|
||
<!-- TODO -->
|
||
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/45-nil-receiver/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="using-a-filename-as-a-function-input-46">Using a filename as a function input (#46)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Designing functions to receive <code>io.Reader</code> types instead of filenames improves the reusability of a function and makes testing easier.</p>
|
||
</details>
|
||
<p>Accepting a filename as a function input to read from a file should, in most cases, be considered a code smell (except in specific functions such as <code>os.Open</code>). Indeed, it makes unit tests more complex because we may have to create multiple files. It also reduces the reusability of a function (although not all functions are meant to be reused). Using the <code>io.Reader</code> interface abstracts the data source. Regardless of whether the input is a file, a string, an HTTP request, or a gRPC request, the implementation can be reused and easily tested.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/06-functions-methods/46-function-input/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<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>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<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>
|
||
<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><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>
|
||
<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="hll"><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><span id="__span-28-4"><a id="__codelineno-28-4" name="__codelineno-28-4" href="#__codelineno-28-4"></a><span class="hll"><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><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="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>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-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-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-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-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a><span class="hll"><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span></span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a><span class="hll"><span class="w"> </span><span class="nx">notify</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span>
|
||
</span></span><span id="__span-29-5"><a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a><span class="hll"><span class="w"> </span><span class="nx">incrementCounter</span><span class="p">(</span><span class="nx">status</span><span class="p">)</span>
|
||
</span></span><span id="__span-29-6"><a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a><span class="hll"><span class="w"> </span><span class="p">}()</span>
|
||
</span></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><span class="w"> </span><span class="c1">// The rest of the function unchanged</span>
|
||
</span><span id="__span-29-9"><a id="__codelineno-29-9" name="__codelineno-29-9" href="#__codelineno-29-9"></a><span class="p">}</span>
|
||
</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/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="error-management">Error Management</h2>
|
||
<h3 id="panicking-48">Panicking (#48)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<p>In Go, panic is a built-in function that stops the ordinary flow:</p>
|
||
<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>
|
||
<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 mandatory 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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="ignoring-when-to-wrap-an-error-49">Ignoring when to wrap an error (#49)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Wrapping an error allows you to mark an error and/or provide additional context. However, error wrapping creates potential coupling as it makes the source error available for the caller. If you want to prevent that, don’t use error wrapping.</p>
|
||
</details>
|
||
<p>Since Go 1.13, the %w directive allows us to wrap errors conveniently. Error wrapping is about wrapping or packing an error inside a wrapper container that also makes the source error available. In general, the two main use cases for error wrapping are the following:</p>
|
||
<ul>
|
||
<li>Adding additional context to an error</li>
|
||
<li>Marking an error as a specific error</li>
|
||
</ul>
|
||
<p>When handling an error, we can decide to wrap it. Wrapping is about adding additional context to an error and/or marking an error as a specific type. If we need to mark an error, we should create a custom error type. However, if we just want to add extra context, we should use fmt.Errorf with the %w directive as it doesn’t require creating a new error type. Yet, error wrapping creates potential coupling as it makes the source error available for the caller. If we want to prevent it, we shouldn’t use error wrapping but error transformation, for example, using fmt.Errorf with the %v directive.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/49-error-wrapping/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="comparing-an-error-type-inaccurately-50">Comparing an error type inaccurately (#50)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>If you use Go 1.13 error wrapping with the <code>%w</code> directive and <code>fmt.Errorf</code>, comparing an error against a type 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>
|
||
</details>
|
||
<!-- TODO -->
|
||
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/50-compare-error-type/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="comparing-an-error-value-inaccurately-51">Comparing an error value inaccurately (#51)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<p>A sentinel error is an error defined as a global variable:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-32-1"><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="kn">import</span><span class="w"> </span><span class="s">"errors"</span>
|
||
</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><span class="kd">var</span><span class="w"> </span><span class="nx">ErrFoo</span><span class="w"> </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">"foo"</span><span class="p">)</span>
|
||
</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>
|
||
<li>Unexpected errors should be designed as error types: <code>type BarError struct { ... }</code>, with <code>BarError</code> implementing the <code>error</code> interface.</li>
|
||
</ul>
|
||
<p>If we use error wrapping in our application with the <code>%w</code> directive and <code>fmt.Errorf</code>, checking an error against a specific value should be done using <code>errors.Is</code> instead of <code>==</code>. Thus, even if the sentinel error is wrapped, <code>errors.Is</code> can recursively unwrap it and compare each error in the chain against the provided value.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/51-comparing-error-value/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="handling-an-error-twice-52">Handling an error twice (#52)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>In most situations, an error should be handled only once. Logging an error is handling an error. Therefore, you have to choose between logging or returning an error. In many cases, error wrapping is the solution as it allows you to provide additional context to an error and return the source error.</p>
|
||
</details>
|
||
<p>Handling an error multiple times is a mistake made frequently by developers, not specifically in Go. This can cause situations where the same error is logged multiple times make debugging harder.</p>
|
||
<p>Let's remind us that handling an error should be done only once. Logging an error is handling an error. Hence, we should either log or return an error. By doing this, we simplify our code and gain better insights into the error situation. Using error wrapping is the most convenient approach as it allows us to propagate the source error and add context to an error.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/52-handling-error-twice/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-handling-an-error-53">Not handling an error (#53)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Ignoring an error, whether during a function call or in a <code>defer</code> function, should be done explicitly using the blank identifier. Otherwise, future readers may be confused about whether it was intentional or a miss.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/07-error-management/53-not-handling-error/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-handling-defer-errors-54">Not handling <code>defer</code> errors (#54)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>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>
|
||
</details>
|
||
<p>Consider the following code:</p>
|
||
<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>
|
||
<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>
|
||
<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"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> 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>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding the fundamental differences between concurrency and parallelism is a cornerstone of the Go developer’s knowledge. Concurrency is about structure, whereas parallelism is about execution.</p>
|
||
</details>
|
||
<p>Concurrency and parallelism are not the same:</p>
|
||
<ul>
|
||
<li>Concurrency is about structure. We can change a sequential implementation into a concurrent one by introducing different steps that separate concurrent goroutines can tackle.</li>
|
||
<li>Meanwhile, parallelism is about execution. We can use parallism at the steps level by adding more parallel goroutines.</li>
|
||
</ul>
|
||
<p>In summary, concurrency provides a structure to solve a problem with parts that may be parallelized. Therefore, <em>concurrency enables parallelism</em>.</p>
|
||
<!-- TODO Include Rob Pike's talk link-->
|
||
|
||
<h3 id="thinking-concurrency-is-always-faster-56">Thinking concurrency is always faster (#56)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To be a proficient developer, you must acknowledge that concurrency isn’t always faster. Solutions involving parallelization of minimal workloads may not necessarily be faster than a sequential implementation. Benchmarking sequential versus concurrent solutions should be the way to validate assumptions.</p>
|
||
</details>
|
||
<p>Read the full section <a href="56-concurrency-faster/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/08-concurrency-foundations/56-faster/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="being-puzzled-about-when-to-use-channels-or-mutexes-57">Being puzzled about when to use channels or mutexes (#57)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Being aware of goroutine interactions can also be helpful when deciding between channels and mutexes. In general, parallel goroutines require synchronization and hence mutexes. Conversely, concurrent goroutines generally require coordination and orchestration and hence channels.</p>
|
||
</details>
|
||
<p>Given a concurrency problem, it may not always be clear whether we can implement a
|
||
solution using channels or mutexes. Because Go promotes sharing memory by communication, one mistake could be to always force the use of channels, regardless of
|
||
the use case. However, we should see the two options as complementary. </p>
|
||
<p>When should we use channels or mutexes? We will use the example in the next figure as a backbone. Our example has three different goroutines with specific relationships:</p>
|
||
<ul>
|
||
<li>G1 and G2 are parallel goroutines. They may be two goroutines executing the same function that keeps receiving messages from a channel, or perhaps two goroutines executing the same HTTP handler at the same time.</li>
|
||
<li>On the other hand, G1 and G3 are concurrent goroutines, as are G2 and G3. All the goroutines are part of an overall concurrent structure, but G1 and G2 perform the first step, whereas G3 does the next step.</li>
|
||
</ul>
|
||
<!-- TODO Include figure-->
|
||
|
||
<p>In general, parallel goroutines have to <em>synchronize</em>: for example, when they need to access or mutate a shared resource such as a slice. Synchronization is enforced with mutexes but not with any channel types (not with buffered channels). Hence, in general, synchronization between parallel goroutines should be achieved via mutexes.</p>
|
||
<p>Conversely, in general, concurrent goroutines have to <em>coordinate and orchestrate</em>. For example, if G3 needs to aggregate results from both G1 and G2, G1 and G2 need to signal to G3 that a new intermediate result is available. This coordination falls under the scope of communication—therefore, channels.</p>
|
||
<p>Regarding concurrent goroutines, there’s also the case where we want to transfer the ownership of a resource from one step (G1 and G2) to another (G3); for example, if G1 and G2 are enriching a shared resource and at some point, we consider this job as complete. Here, we should use channels to signal that a specific resource is ready and handle the ownership transfer.</p>
|
||
<p>Mutexes and channels have different semantics. Whenever we want to share a state or access a shared resource, mutexes ensure exclusive access to this resource. Conversely, channels are a mechanic for signaling with or without data (<code>chan struct{}</code> or not). Coordination or ownership transfer should be achieved via channels. It’s important to know whether goroutines are parallel or concurrent because, in general, we need mutexes for parallel goroutines and channels for concurrent ones.</p>
|
||
<h3 id="not-understanding-race-problems-data-races-vs-race-conditions-and-the-go-memory-model-58">Not understanding race problems (data races vs. race conditions and the Go memory model) (#58)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Being proficient in concurrency also means understanding that data races and race conditions are different concepts. Data races occur when multiple goroutines simultaneously access the same memory location and at least one of them is writing. Meanwhile, being data-race-free doesn’t necessarily mean deterministic execution. When a behavior depends on the sequence or the timing of events that can’t be controlled, this is a race condition.</p>
|
||
</details>
|
||
<p>Race problems can be among the hardest and most insidious bugs a programmer can face. As Go developers, we must understand crucial aspects such as data races and race conditions, their possible impacts, and how to avoid them.</p>
|
||
<h4 id="data-race">Data Race</h4>
|
||
<p>A data race occurs when two or more goroutines simultaneously access the same memory location and at least one is writing. In this case, the result can be hazardous. Even worse, in some situations, the memory location may end up holding a value containing a meaningless combination of bits.</p>
|
||
<p>We can prevent a data race from happening using different techniques. For example: </p>
|
||
<ul>
|
||
<li>Using the <code>sync/atomic</code> package</li>
|
||
<li>In synchronizing the two goroutines with an ad hoc data structure like a mutex</li>
|
||
<li>Using channels to make the two goroutines communicating to ensure that a variable is updated by only one goroutine at a time</li>
|
||
</ul>
|
||
<h4 id="race-condition">Race Condition</h4>
|
||
<p>Depending on the operation we want to perform, does a data-race-free application necessarily mean a deterministic result? Not necessarily.</p>
|
||
<p>A race condition occurs when the behavior depends on the sequence or the timing of events that can’t be controlled. Here, the timing of events is the goroutines’ execution order.</p>
|
||
<p>In summary, when we work in concurrent applications, it’s essential to understand that a data race is different from a race condition. A data race occurs when multiple goroutines simultaneously access the same memory location and at least one of them is writing. A data race means unexpected behavior. However, a data-race-free application doesn’t necessarily mean deterministic results. An application can be free of data races but still have behavior that depends on uncontrolled events (such as goroutine execution, how fast a message is published to a channel, or how long a call to a database lasts); this is a race condition. Understanding both concepts is crucial to becoming proficient in designing concurrent applications.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/08-concurrency-foundations/58-races/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-understanding-the-concurrency-impacts-of-a-workload-type-59">Not understanding the concurrency impacts of a workload type (#59)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>When creating a certain number of goroutines, consider the workload type. Creating CPU-bound goroutines means bounding this number close to the <abbr title="The variable defines the limit of OS threads in charge of executing user-level code simultaneously">GOMAXPROCS</abbr> variable (based by default on the number of CPU cores on the host). Creating I/O-bound goroutines depends on other factors, such as the external system.</p>
|
||
</details>
|
||
<p>In programming, the execution time of a workload is limited by one of the following:</p>
|
||
<ul>
|
||
<li>The speed of the CPU—For example, running a merge sort algorithm. The workload is called CPU-bound.</li>
|
||
<li>The speed of I/O—For example, making a REST call or a database query. The workload is called I/O-bound.</li>
|
||
<li>The amount of available memory—The workload is called memory-bound.</li>
|
||
</ul>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p>The last is the rarest nowadays, given that memory has become very cheap in recent decades. Hence, this section focuses on the two first workload types: CPU- and I/O-bound.</p>
|
||
</details>
|
||
<p>If the workload executed by the workers is I/O-bound, the value mainly depends on the external system. Conversely, if the workload is CPU-bound, the optimal number of goroutines is close to the number of available CPU cores (a best practice can be to use <code>runtime.GOMAXPROCS</code>). Knowing the workload type (I/O or CPU) is crucial when designing concurrent applications.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/08-concurrency-foundations/59-workload-type/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="misunderstanding-go-contexts-60">Misunderstanding Go contexts (#60)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Go contexts are also one of the cornerstones of concurrency in Go. A context allows you to carry a deadline, a cancellation signal, and/or a list of keys-values.</p>
|
||
</details>
|
||
<div class="admonition quote">
|
||
<p class="admonition-title">https://pkg.go.dev/context</p>
|
||
<p>A Context carries a deadline, a cancellation signal, and other values across API boundaries.</p>
|
||
</div>
|
||
<h4 id="deadline">Deadline</h4>
|
||
<p>A deadline refers to a specific point in time determined with one of the following:</p>
|
||
<ul>
|
||
<li>A <code>time.Duration</code> from now (for example, in 250 ms)</li>
|
||
<li>A <code>time.Time</code> (for example, 2023-02-07 00:00:00 UTC)</li>
|
||
</ul>
|
||
<p>The semantics of a deadline convey that an ongoing activity should be stopped if this deadline is met. An activity is, for example, an I/O request or a goroutine waiting to receive a message from a channel.</p>
|
||
<h4 id="cancellation-signals">Cancellation signals</h4>
|
||
<p>Another use case for Go contexts is to carry a cancellation signal. Let’s imagine that we want to create an application that calls <code>CreateFileWatcher(ctx context.Context, filename string)</code> within another goroutine. This function creates a specific file watcher that keeps reading from a file and catches updates. When the provided context expires or is canceled, this function handles it to close the file descriptor.</p>
|
||
<h4 id="context-values">Context values</h4>
|
||
<p>The last use case for Go contexts is to carry a key-value list. What’s the point of having a context carrying a key-value list? Because Go contexts are generic and mainstream, there are infinite use cases.</p>
|
||
<p>For example, if we use tracing, we may want different subfunctions to share the same correlation ID. Some developers may consider this ID too invasive to be part of the function signature. In this regard, we could also decide to include it as part of the provided context.</p>
|
||
<h4 id="catching-a-context-cancellation">Catching a context cancellation</h4>
|
||
<p>The <code>context.Context</code> type exports a <code>Done</code> method that returns a receive-only notification channel: <code><-chan struct{}</code>. This channel is closed when the work associated with the context should be canceled. For example,</p>
|
||
<ul>
|
||
<li>The Done channel related to a context created with <code>context.WithCancel</code> is closed when the cancel function is called.</li>
|
||
<li>The Done channel related to a context created with <code>context.WithDeadline</code> is closed when the deadline has expired.</li>
|
||
</ul>
|
||
<p>One thing to note is that the internal channel should be closed when a context is canceled or has met a deadline, instead of when it receives a specific value, because the closure of a channel is the only channel action that all the consumer goroutines will receive. This way, all the consumers will be notified once a context is canceled or a deadline is reached.</p>
|
||
<p>In summary, to be a proficient Go developer, we have to understand what a context is and how to use it. In general, a function that users wait for should take a context, as doing so allows upstream callers to decide when calling this function should be aborted. </p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/08-concurrency-foundations/60-contexts/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="concurrency-practice">Concurrency: Practice</h2>
|
||
<h3 id="propagating-an-inappropriate-context-61">Propagating an inappropriate context (#61)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding the conditions when a context can be canceled should matter when propagating it: for example, an HTTP handler canceling the context when the response has been sent.</p>
|
||
</details>
|
||
<p>In many situations, it is recommended to propagate Go contexts. However, context propagation can sometimes lead to subtle bugs, preventing subfunctions from being correctly executed.</p>
|
||
<p>Let’s consider the following example. We expose an HTTP handler that performs some tasks and returns a response. But just before returning the response, we also want to send it to a Kafka topic. We don’t want to penalize the HTTP consumer latency-wise, so we want the publish action to be handled asynchronously within a new goroutine. We assume that we have at our disposal a <code>publish</code> function that accepts a context so the action of publishing a message can be interrupted if the context is canceled, for example. Here is a possible implementation:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-36-1"><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">handler</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-36-2"><a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a><span class="w"> </span><span class="nx">response</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">doSomeTask</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">Context</span><span class="p">(),</span><span class="w"> </span><span class="nx">r</span><span class="p">)</span>
|
||
</span><span id="__span-36-3"><a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-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="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-36-4"><a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">(),</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusInternalServerError</span><span class="p">)</span>
|
||
</span><span id="__span-36-5"><a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a><span class="w"> </span><span class="k">return</span>
|
||
</span><span id="__span-36-6"><a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-36-7"><a id="__codelineno-36-7" name="__codelineno-36-7" href="#__codelineno-36-7"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-36-8"><a id="__codelineno-36-8" name="__codelineno-36-8" href="#__codelineno-36-8"></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">publish</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">Context</span><span class="p">(),</span><span class="w"> </span><span class="nx">response</span><span class="p">)</span>
|
||
</span><span id="__span-36-9"><a id="__codelineno-36-9" name="__codelineno-36-9" href="#__codelineno-36-9"></a><span class="w"> </span><span class="c1">// Do something with err</span>
|
||
</span><span id="__span-36-10"><a id="__codelineno-36-10" name="__codelineno-36-10" href="#__codelineno-36-10"></a><span class="w"> </span><span class="p">}()</span>
|
||
</span><span id="__span-36-11"><a id="__codelineno-36-11" name="__codelineno-36-11" href="#__codelineno-36-11"></a><span class="w"> </span><span class="nx">writeResponse</span><span class="p">(</span><span class="nx">response</span><span class="p">)</span>
|
||
</span><span id="__span-36-12"><a id="__codelineno-36-12" name="__codelineno-36-12" href="#__codelineno-36-12"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>What’s wrong with this piece of code? We have to know that the context attached to an HTTP request can cancel in different conditions:</p>
|
||
<ul>
|
||
<li>When the client’s connection closes</li>
|
||
<li>In the case of an HTTP/2 request, when the request is canceled</li>
|
||
<li>When the response has been written back to the client</li>
|
||
</ul>
|
||
<p>In the first two cases, we probably handle things correctly. For example, if we get a response from doSomeTask but the client has closed the connection, it’s probably OK to call publish with a context already canceled so the message isn’t published. But what about the last case?</p>
|
||
<p>When the response has been written to the client, the context associated with the request will be canceled. Therefore, we are facing a race condition:</p>
|
||
<ul>
|
||
<li>If the response is written after the Kafka publication, we both return a response and publish a message successfully</li>
|
||
<li>However, if the response is written before or during the Kafka publication, the message shouldn’t be published.</li>
|
||
</ul>
|
||
<p>In the latter case, calling publish will return an error because we returned the HTTP response quickly.</p>
|
||
<details class="note" open="open">
|
||
<summary>Note</summary>
|
||
<p>From Go 1.21, there is a way to create a new context without cancel. <a href="https://pkg.go.dev/context#WithoutCancel"><code>context.WithoutCancel</code></a> returns a copy of parent that is not canceled when parent is canceled.</p>
|
||
</details>
|
||
<p>In summary, propagating a context should be done cautiously.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/61-inappropriate-context/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="starting-a-goroutine-without-knowing-when-to-stop-it-62">Starting a goroutine without knowing when to stop it (#62)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Avoiding leaks means being mindful that whenever a goroutine is started, you should have a plan to stop it eventually.</p>
|
||
</details>
|
||
<p>Goroutines are easy and cheap to start—so easy and cheap that we may not necessarily have a plan for when to stop a new goroutine, which can lead to leaks. Not knowing when to stop a goroutine is a design issue and a common concurrency mistake in Go.</p>
|
||
<p>Let’s discuss a concrete example. We will design an application that needs to watch some external configuration (for example, using a database connection). Here’s a first implementation:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-37-1"><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-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-37-2"><a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a><span class="w"> </span><span class="nx">newWatcher</span><span class="p">()</span>
|
||
</span><span id="__span-37-3"><a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a><span class="w"> </span><span class="c1">// Run the application</span>
|
||
</span><span id="__span-37-4"><a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a><span class="p">}</span>
|
||
</span><span id="__span-37-5"><a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a>
|
||
</span><span id="__span-37-6"><a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a><span class="kd">type</span><span class="w"> </span><span class="nx">watcher</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="cm">/* Some resources */</span><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-37-7"><a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a>
|
||
</span><span id="__span-37-8"><a id="__codelineno-37-8" name="__codelineno-37-8" href="#__codelineno-37-8"></a><span class="kd">func</span><span class="w"> </span><span class="nx">newWatcher</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-37-9"><a id="__codelineno-37-9" name="__codelineno-37-9" href="#__codelineno-37-9"></a><span class="w"> </span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">watcher</span><span class="p">{}</span>
|
||
</span><span id="__span-37-10"><a id="__codelineno-37-10" name="__codelineno-37-10" href="#__codelineno-37-10"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nx">watch</span><span class="p">()</span><span class="w"> </span><span class="c1">// Creates a goroutine that watches some external configuration</span>
|
||
</span><span id="__span-37-11"><a id="__codelineno-37-11" name="__codelineno-37-11" href="#__codelineno-37-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>The problem with this code is that when the main goroutine exits (perhaps because of an OS signal or because it has a finite workload), the application is stopped. Hence, the resources created by watcher aren’t closed gracefully. How can we prevent this from happening?</p>
|
||
<p>One option could be to pass to newWatcher a context that will be canceled when main returns:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-38-1"><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-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-38-2"><a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a><span class="w"> </span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">cancel</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">WithCancel</span><span class="p">(</span><span class="nx">context</span><span class="p">.</span><span class="nx">Background</span><span class="p">())</span>
|
||
</span><span id="__span-38-3"><a id="__codelineno-38-3" name="__codelineno-38-3" href="#__codelineno-38-3"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">cancel</span><span class="p">()</span>
|
||
</span><span id="__span-38-4"><a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a><span class="w"> </span><span class="nx">newWatcher</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
|
||
</span><span id="__span-38-5"><a id="__codelineno-38-5" name="__codelineno-38-5" href="#__codelineno-38-5"></a><span class="w"> </span><span class="c1">// Run the application</span>
|
||
</span><span id="__span-38-6"><a id="__codelineno-38-6" name="__codelineno-38-6" href="#__codelineno-38-6"></a><span class="p">}</span>
|
||
</span><span id="__span-38-7"><a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a>
|
||
</span><span id="__span-38-8"><a id="__codelineno-38-8" name="__codelineno-38-8" href="#__codelineno-38-8"></a><span class="kd">func</span><span class="w"> </span><span class="nx">newWatcher</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="p">{</span>
|
||
</span><span id="__span-38-9"><a id="__codelineno-38-9" name="__codelineno-38-9" href="#__codelineno-38-9"></a><span class="w"> </span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">watcher</span><span class="p">{}</span>
|
||
</span><span id="__span-38-10"><a id="__codelineno-38-10" name="__codelineno-38-10" href="#__codelineno-38-10"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nx">watch</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
|
||
</span><span id="__span-38-11"><a id="__codelineno-38-11" name="__codelineno-38-11" href="#__codelineno-38-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>We propagate the context created to the watch method. When the context is canceled, the watcher struct should close its resources. However, can we guarantee that watch will have time to do so? Absolutely not—and that’s a design flaw.</p>
|
||
<p>The problem is that we used signaling to convey that a goroutine had to be stopped. We didn’t block the parent goroutine until the resources had been closed. Let’s make sure we do:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-39-1"><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-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-39-2"><a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a><span class="w"> </span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">newWatcher</span><span class="p">()</span>
|
||
</span><span id="__span-39-3"><a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nb">close</span><span class="p">()</span>
|
||
</span><span id="__span-39-4"><a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a><span class="w"> </span><span class="c1">// Run the application</span>
|
||
</span><span id="__span-39-5"><a id="__codelineno-39-5" name="__codelineno-39-5" href="#__codelineno-39-5"></a><span class="p">}</span>
|
||
</span><span id="__span-39-6"><a id="__codelineno-39-6" name="__codelineno-39-6" href="#__codelineno-39-6"></a>
|
||
</span><span id="__span-39-7"><a id="__codelineno-39-7" name="__codelineno-39-7" href="#__codelineno-39-7"></a><span class="kd">func</span><span class="w"> </span><span class="nx">newWatcher</span><span class="p">()</span><span class="w"> </span><span class="nx">watcher</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-39-8"><a id="__codelineno-39-8" name="__codelineno-39-8" href="#__codelineno-39-8"></a><span class="w"> </span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">watcher</span><span class="p">{}</span>
|
||
</span><span id="__span-39-9"><a id="__codelineno-39-9" name="__codelineno-39-9" href="#__codelineno-39-9"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nx">watch</span><span class="p">()</span>
|
||
</span><span id="__span-39-10"><a id="__codelineno-39-10" name="__codelineno-39-10" href="#__codelineno-39-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">w</span>
|
||
</span><span id="__span-39-11"><a id="__codelineno-39-11" name="__codelineno-39-11" href="#__codelineno-39-11"></a><span class="p">}</span>
|
||
</span><span id="__span-39-12"><a id="__codelineno-39-12" name="__codelineno-39-12" href="#__codelineno-39-12"></a>
|
||
</span><span id="__span-39-13"><a id="__codelineno-39-13" name="__codelineno-39-13" href="#__codelineno-39-13"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">watcher</span><span class="p">)</span><span class="w"> </span><span class="nb">close</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-39-14"><a id="__codelineno-39-14" name="__codelineno-39-14" href="#__codelineno-39-14"></a><span class="w"> </span><span class="c1">// Close the resources</span>
|
||
</span><span id="__span-39-15"><a id="__codelineno-39-15" name="__codelineno-39-15" href="#__codelineno-39-15"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Instead of signaling <code>watcher</code> that it’s time to close its resources, we now call this <code>close</code> method, using <code>defer</code> to guarantee that the resources are closed before the application exits.</p>
|
||
<p>In summary, let’s be mindful that a goroutine is a resource like any other that must eventually be closed to free memory or other resources. Starting a goroutine without knowing when to stop it is a design issue. Whenever a goroutine is started, we should have a clear plan about when it will stop. Last but not least, if a goroutine creates resources and its lifetime is bound to the lifetime of the application, it’s probably safer to wait for this goroutine to complete before exiting the application. This way, we can ensure that the resources can be freed.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/62-starting-goroutine/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-being-careful-with-goroutines-and-loop-variables-63"><img alt="⚠" class="twemoji" src="https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.0.3/assets/svg/26a0.svg" title=":warning:" /> Not being careful with goroutines and loop variables (#63)</h3>
|
||
<details class="warning" open="open">
|
||
<summary>Warning</summary>
|
||
<p>This mistake isn't relevant anymore from Go 1.22 (<a href="https://go.dev/blog/loopvar-preview">details</a>).</p>
|
||
</details>
|
||
<h3 id="expecting-a-deterministic-behavior-using-select-and-channels-64">Expecting a deterministic behavior using select and channels (#64)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding that <code>select</code> with multiple channels chooses the case randomly if multiple options are possible prevents making wrong assumptions that can lead to subtle concurrency bugs.</p>
|
||
</details>
|
||
<p>One common mistake made by Go developers while working with channels is to make wrong assumptions about how select behaves with multiple channels.</p>
|
||
<p>For example, let's consider the following case (<code>disconnectCh</code> is a unbuffered channel):</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-40-1"><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-40-2"><a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-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">10</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-40-3"><a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a><span class="w"> </span><span class="nx">messageCh</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nx">i</span>
|
||
</span><span id="__span-40-4"><a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-40-5"><a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a><span class="w"> </span><span class="nx">disconnectCh</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kd">struct</span><span class="p">{}{}</span>
|
||
</span><span id="__span-40-6"><a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a><span class="p">}()</span>
|
||
</span><span id="__span-40-7"><a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a>
|
||
</span><span id="__span-40-8"><a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="k">for</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-40-9"><a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a><span class="w"> </span><span class="k">select</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-40-10"><a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o"><-</span><span class="nx">messageCh</span><span class="p">:</span>
|
||
</span><span id="__span-40-11"><a id="__codelineno-40-11" name="__codelineno-40-11" href="#__codelineno-40-11"></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-40-12"><a id="__codelineno-40-12" name="__codelineno-40-12" href="#__codelineno-40-12"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="o"><-</span><span class="nx">disconnectCh</span><span class="p">:</span>
|
||
</span><span id="__span-40-13"><a id="__codelineno-40-13" name="__codelineno-40-13" href="#__codelineno-40-13"></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">"disconnection, return"</span><span class="p">)</span>
|
||
</span><span id="__span-40-14"><a id="__codelineno-40-14" name="__codelineno-40-14" href="#__codelineno-40-14"></a><span class="w"> </span><span class="k">return</span>
|
||
</span><span id="__span-40-15"><a id="__codelineno-40-15" name="__codelineno-40-15" href="#__codelineno-40-15"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-40-16"><a id="__codelineno-40-16" name="__codelineno-40-16" href="#__codelineno-40-16"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>If we run this example multiple times, the result will be random:</p>
|
||
<div class="language-text highlight"><pre><span></span><code><span id="__span-41-1"><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a>0
|
||
</span><span id="__span-41-2"><a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a>1
|
||
</span><span id="__span-41-3"><a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a>2
|
||
</span><span id="__span-41-4"><a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a>disconnection, return
|
||
</span><span id="__span-41-5"><a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a>
|
||
</span><span id="__span-41-6"><a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a>0
|
||
</span><span id="__span-41-7"><a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a>disconnection, return
|
||
</span></code></pre></div>
|
||
<p>Instead of consuming the 10 messages, we only received a few of them. What’s the reason? It lies in the specification of the select statement with multiple channels (https:// go.dev/ref/spec):</p>
|
||
<div class="admonition quote">
|
||
<p class="admonition-title">Quote</p>
|
||
<p>If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.</p>
|
||
</div>
|
||
<p>Unlike a switch statement, where the first case with a match wins, the select statement selects randomly if multiple options are possible.</p>
|
||
<p>This behavior might look odd at first, but there’s a good reason for it: to prevent possible starvation. Suppose the first possible communication chosen is based on the source order. In that case, we may fall into a situation where, for example, we only receive from one channel because of a fast sender. To prevent this, the language designers decided to use a random selection.</p>
|
||
<p>When using <code>select</code> with multiple channels, we must remember that if multiple options are possible, the first case in the source order does not automatically win. Instead, Go selects randomly, so there’s no guarantee about which option will be chosen. To overcome this behavior, in the case of a single producer goroutine, we can use either unbuffered channels or a single channel.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/64-select-behavior/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-using-notification-channels-65">Not using notification channels (#65)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Send notifications using a <code>chan struct{}</code> type.</p>
|
||
</details>
|
||
<p>Channels are a mechanism for communicating across goroutines via signaling. A signal can be either with or without data.</p>
|
||
<p>Let’s look at a concrete example. We will create a channel that will notify us whenever a certain disconnection occurs. One idea is to handle it as a <code>chan bool</code>:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-42-1"><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a><span class="nx">disconnectCh</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span>
|
||
</span></code></pre></div>
|
||
<p>Now, let’s say we interact with an API that provides us with such a channel. Because it’s a channel of Booleans, we can receive either <code>true</code> or <code>false</code> messages. It’s probably clear what <code>true</code> conveys. But what does <code>false</code> mean? Does it mean we haven’t been disconnected? And in this case, how frequently will we receive such a signal? Does it mean we have reconnected? Should we even expect to receive <code>false</code>? Perhaps we should only expect to receive <code>true</code> messages.</p>
|
||
<p>If that’s the case, meaning we don’t need a specific value to convey some information, we need a channel <em>without</em> data. The idiomatic way to handle it is a channel of empty structs: <code>chan struct{}</code>.</p>
|
||
<h3 id="not-using-nil-channels-66">Not using nil channels (#66)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Using nil channels should be part of your concurrency toolset because it allows you to <em>remove</em> cases from <code>select</code> statements, for example.</p>
|
||
</details>
|
||
<p>What should this code do?</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-43-1"><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span>
|
||
</span><span id="__span-43-2"><a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a><span class="o"><-</span><span class="nx">ch</span>
|
||
</span></code></pre></div>
|
||
<p><code>ch</code> is a <code>chan int</code> type. The zero value of a channel being nil, <code>ch</code> is <code>nil</code>. The goroutine won’t panic; however, it will block forever.</p>
|
||
<p>The principle is the same if we send a message to a nil channel. This goroutine blocks forever:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-44-1"><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span>
|
||
</span><span id="__span-44-2"><a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="nx">ch</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="mi">0</span>
|
||
</span></code></pre></div>
|
||
<p>Then what’s the purpose of Go allowing messages to be received from or sent to a nil channel? For example, we can use nil channels to implement an idiomatic way to merge two channels:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-45-1"><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">merge</span><span class="p">(</span><span class="nx">ch1</span><span class="p">,</span><span class="w"> </span><span class="nx">ch2</span><span class="w"> </span><span class="o"><-</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-45-2"><a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-45-3"><a id="__codelineno-45-3" name="__codelineno-45-3" href="#__codelineno-45-3"></a>
|
||
</span><span id="__span-45-4"><a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-45-5"><a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="hll"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">ch1</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nx">ch2</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="c1">// Continue if at least one channel isn’t nil</span>
|
||
</span></span><span id="__span-45-6"><a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a><span class="w"> </span><span class="k">select</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-45-7"><a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">open</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o"><-</span><span class="nx">ch1</span><span class="p">:</span>
|
||
</span><span id="__span-45-8"><a id="__codelineno-45-8" name="__codelineno-45-8" href="#__codelineno-45-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">open</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-45-9"><a id="__codelineno-45-9" name="__codelineno-45-9" href="#__codelineno-45-9"></a><span class="hll"><span class="w"> </span><span class="nx">ch1</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="c1">// Assign ch1 to a nil channel once closed</span>
|
||
</span></span><span id="__span-45-10"><a id="__codelineno-45-10" name="__codelineno-45-10" href="#__codelineno-45-10"></a><span class="w"> </span><span class="k">break</span>
|
||
</span><span id="__span-45-11"><a id="__codelineno-45-11" name="__codelineno-45-11" href="#__codelineno-45-11"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-45-12"><a id="__codelineno-45-12" name="__codelineno-45-12" href="#__codelineno-45-12"></a><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nx">v</span>
|
||
</span><span id="__span-45-13"><a id="__codelineno-45-13" name="__codelineno-45-13" href="#__codelineno-45-13"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">open</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="o"><-</span><span class="nx">ch2</span><span class="p">:</span>
|
||
</span><span id="__span-45-14"><a id="__codelineno-45-14" name="__codelineno-45-14" href="#__codelineno-45-14"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">open</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-45-15"><a id="__codelineno-45-15" name="__codelineno-45-15" href="#__codelineno-45-15"></a><span class="hll"><span class="w"> </span><span class="nx">ch2</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="c1">// Assigns ch2 to a nil channel once closed</span>
|
||
</span></span><span id="__span-45-16"><a id="__codelineno-45-16" name="__codelineno-45-16" href="#__codelineno-45-16"></a><span class="w"> </span><span class="k">break</span>
|
||
</span><span id="__span-45-17"><a id="__codelineno-45-17" name="__codelineno-45-17" href="#__codelineno-45-17"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-45-18"><a id="__codelineno-45-18" name="__codelineno-45-18" href="#__codelineno-45-18"></a><span class="w"> </span><span class="nx">ch</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nx">v</span>
|
||
</span><span id="__span-45-19"><a id="__codelineno-45-19" name="__codelineno-45-19" href="#__codelineno-45-19"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-45-20"><a id="__codelineno-45-20" name="__codelineno-45-20" href="#__codelineno-45-20"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-45-21"><a id="__codelineno-45-21" name="__codelineno-45-21" href="#__codelineno-45-21"></a><span class="w"> </span><span class="nb">close</span><span class="p">(</span><span class="nx">ch</span><span class="p">)</span>
|
||
</span><span id="__span-45-22"><a id="__codelineno-45-22" name="__codelineno-45-22" href="#__codelineno-45-22"></a><span class="w"> </span><span class="p">}()</span>
|
||
</span><span id="__span-45-23"><a id="__codelineno-45-23" name="__codelineno-45-23" href="#__codelineno-45-23"></a>
|
||
</span><span id="__span-45-24"><a id="__codelineno-45-24" name="__codelineno-45-24" href="#__codelineno-45-24"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">ch</span>
|
||
</span><span id="__span-45-25"><a id="__codelineno-45-25" name="__codelineno-45-25" href="#__codelineno-45-25"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>This elegant solution relies on nil channels to somehow <em>remove</em> one case from the <code>select</code> statement.</p>
|
||
<p>Let’s keep this idea in mind: nil channels are useful in some conditions and should be part of the Go developer’s toolset when dealing with concurrent code.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/66-nil-channels/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="being-puzzled-about-channel-size-67">Being puzzled about channel size (#67)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Carefully decide on the right channel type to use, given a problem. Only unbuffered channels provide strong synchronization guarantees. For buffered channels, you should have a good reason to specify a channel size other than one.</p>
|
||
</details>
|
||
<p>An unbuffered channel is a channel without any capacity. It can be created by either omitting the size or providing a 0 size:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-46-1"><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="nx">ch1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span>
|
||
</span><span id="__span-46-2"><a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a><span class="nx">ch2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||
</span></code></pre></div>
|
||
<p>With an unbuffered channel (sometimes called a synchronous channel), the sender will block until the receiver receives data from the channel.</p>
|
||
<p>Conversely, a buffered channel has a capacity, and it must be created with a size greater than or equal to 1:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-47-1"><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a><span class="nx">ch3</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span></code></pre></div>
|
||
<p>With a buffered channel, a sender can send messages while the channel isn’t full. Once the channel is full, it will block until a receiver goroutine receives a message:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-48-1"><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a><span class="nx">ch3</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">chan</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-48-2"><a id="__codelineno-48-2" name="__codelineno-48-2" href="#__codelineno-48-2"></a><span class="nx">ch3</span><span class="w"> </span><span class="o"><-</span><span class="mi">1</span><span class="w"> </span><span class="c1">// Non-blocking</span>
|
||
</span><span id="__span-48-3"><a id="__codelineno-48-3" name="__codelineno-48-3" href="#__codelineno-48-3"></a><span class="nx">ch3</span><span class="w"> </span><span class="o"><-</span><span class="mi">2</span><span class="w"> </span><span class="c1">// Blocking</span>
|
||
</span></code></pre></div>
|
||
<p>The first send isn’t blocking, whereas the second one is, as the channel is full at this stage.</p>
|
||
<p>What's the main difference between unbuffered and buffered channels:</p>
|
||
<ul>
|
||
<li>An unbuffered channel enables synchronization. We have the guarantee that two goroutines will be in a known state: one receiving and another sending a message.</li>
|
||
<li>A buffered channel doesn’t provide any strong synchronization. Indeed, a producer goroutine can send a message and then continue its execution if the channel isn’t full. The only guarantee is that a goroutine won’t receive a message before it is sent. But this is only a guarantee because of causality (you don’t drink your coffee before you prepare it).</li>
|
||
</ul>
|
||
<p>If we need a buffered channel, what size should we provide?</p>
|
||
<p>The default value we should use for buffered channels is its minimum: 1. So, we may approach the problem from this standpoint: is there any good reason not to use a value of 1? Here’s a list of possible cases where we should use another size:</p>
|
||
<ul>
|
||
<li>While using a worker pooling-like pattern, meaning spinning a fixed number of goroutines that need to send data to a shared channel. In that case, we can tie the channel size to the number of goroutines created.</li>
|
||
<li>When using channels for rate-limiting problems. For example, if we need to enforce resource utilization by bounding the number of requests, we should set up the channel size according to the limit.</li>
|
||
</ul>
|
||
<p>If we are outside of these cases, using a different channel size should be done cautiously. Let’s bear in mind that deciding about an accurate queue size isn’t an easy problem:</p>
|
||
<div class="admonition quote">
|
||
<p class="admonition-title">Martin Thompson</p>
|
||
<p>Queues are typically always close to full or close to empty due to the differences in pace between consumers and producers. They very rarely operate in a balanced middle ground where the rate of production and consumption is evenly matched.</p>
|
||
</div>
|
||
<h3 id="forgetting-about-possible-side-effects-with-string-formatting-68">Forgetting about possible side effects with string formatting (#68)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Being aware that string formatting may lead to calling existing functions means watching out for possible deadlocks and other data races.</p>
|
||
</details>
|
||
<p>It’s pretty easy to forget the potential side effects of string formatting while working in a concurrent application.</p>
|
||
<h4 id="etcd-data-race"><a href="https://github.com/etcd-io/etcd">etcd</a> data race</h4>
|
||
<p><a href="https://github.com/etcd-io/etcd/pull/7816">github.com/etcd-io/etcd/pull/7816</a> shows an example of an issue where a map's key was formatted based on a mutable values from a context.</p>
|
||
<h4 id="deadlock">Deadlock</h4>
|
||
<p>Can you see what the problem is in this code with a <code>Customer</code> struct exposing an <code>UpdateAge</code> method and implementing the <code>fmt.Stringer</code> interface?</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-49-1"><a id="__codelineno-49-1" name="__codelineno-49-1" href="#__codelineno-49-1"></a><span class="kd">type</span><span class="w"> </span><span class="nx">Customer</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-49-2"><a id="__codelineno-49-2" name="__codelineno-49-2" href="#__codelineno-49-2"></a><span class="w"> </span><span class="nx">mutex</span><span class="w"> </span><span class="nx">sync</span><span class="p">.</span><span class="nx">RWMutex</span><span class="w"> </span><span class="c1">// Uses a sync.RWMutex to protect concurrent accesses</span>
|
||
</span><span id="__span-49-3"><a id="__codelineno-49-3" name="__codelineno-49-3" href="#__codelineno-49-3"></a><span class="w"> </span><span class="nx">id</span><span class="w"> </span><span class="kt">string</span>
|
||
</span><span id="__span-49-4"><a id="__codelineno-49-4" name="__codelineno-49-4" href="#__codelineno-49-4"></a><span class="w"> </span><span class="nx">age</span><span class="w"> </span><span class="kt">int</span>
|
||
</span><span id="__span-49-5"><a id="__codelineno-49-5" name="__codelineno-49-5" href="#__codelineno-49-5"></a><span class="p">}</span>
|
||
</span><span id="__span-49-6"><a id="__codelineno-49-6" name="__codelineno-49-6" href="#__codelineno-49-6"></a>
|
||
</span><span id="__span-49-7"><a id="__codelineno-49-7" name="__codelineno-49-7" href="#__codelineno-49-7"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Customer</span><span class="p">)</span><span class="w"> </span><span class="nx">UpdateAge</span><span class="p">(</span><span class="nx">age</span><span class="w"> </span><span class="kt">int</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-49-8"><a id="__codelineno-49-8" name="__codelineno-49-8" href="#__codelineno-49-8"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span><span class="w"> </span><span class="c1">// Locks and defers unlock as we update Customer</span>
|
||
</span><span id="__span-49-9"><a id="__codelineno-49-9" name="__codelineno-49-9" href="#__codelineno-49-9"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
|
||
</span><span id="__span-49-10"><a id="__codelineno-49-10" name="__codelineno-49-10" href="#__codelineno-49-10"></a>
|
||
</span><span id="__span-49-11"><a id="__codelineno-49-11" name="__codelineno-49-11" href="#__codelineno-49-11"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">age</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 class="w"> </span><span class="c1">// Returns an error if age is negative</span>
|
||
</span><span id="__span-49-12"><a id="__codelineno-49-12" name="__codelineno-49-12" href="#__codelineno-49-12"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Errorf</span><span class="p">(</span><span class="s">"age should be positive for customer %v"</span><span class="p">,</span><span class="w"> </span><span class="nx">c</span><span class="p">)</span>
|
||
</span><span id="__span-49-13"><a id="__codelineno-49-13" name="__codelineno-49-13" href="#__codelineno-49-13"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-49-14"><a id="__codelineno-49-14" name="__codelineno-49-14" href="#__codelineno-49-14"></a>
|
||
</span><span id="__span-49-15"><a id="__codelineno-49-15" name="__codelineno-49-15" href="#__codelineno-49-15"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">age</span>
|
||
</span><span id="__span-49-16"><a id="__codelineno-49-16" name="__codelineno-49-16" href="#__codelineno-49-16"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||
</span><span id="__span-49-17"><a id="__codelineno-49-17" name="__codelineno-49-17" href="#__codelineno-49-17"></a><span class="p">}</span>
|
||
</span><span id="__span-49-18"><a id="__codelineno-49-18" name="__codelineno-49-18" href="#__codelineno-49-18"></a>
|
||
</span><span id="__span-49-19"><a id="__codelineno-49-19" name="__codelineno-49-19" href="#__codelineno-49-19"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Customer</span><span class="p">)</span><span class="w"> </span><span class="nx">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-49-20"><a id="__codelineno-49-20" name="__codelineno-49-20" href="#__codelineno-49-20"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">RLock</span><span class="p">()</span><span class="w"> </span><span class="c1">// Locks and defers unlock as we read Customer</span>
|
||
</span><span id="__span-49-21"><a id="__codelineno-49-21" name="__codelineno-49-21" href="#__codelineno-49-21"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">RUnlock</span><span class="p">()</span>
|
||
</span><span id="__span-49-22"><a id="__codelineno-49-22" name="__codelineno-49-22" href="#__codelineno-49-22"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">"id %s, age %d"</span><span class="p">,</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">age</span><span class="p">)</span>
|
||
</span><span id="__span-49-23"><a id="__codelineno-49-23" name="__codelineno-49-23" href="#__codelineno-49-23"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>The problem here may not be straightforward. If the provided age is negative, we return an error. Because the error is formatted, using the <code>%s</code> directive on the receiver, it will call the <code>String</code> method to format <code>Customer</code>. But because <code>UpdateAge</code> already acquires the mutex lock, the <code>String</code> method won’t be able to acquire it. Hence, this leads to a deadlock situation. If all goroutines are also asleep, it leads to a panic.</p>
|
||
<p>One possible solution is to restrict the scope of the mutex lock:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-50-1"><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Customer</span><span class="p">)</span><span class="w"> </span><span class="nx">UpdateAge</span><span class="p">(</span><span class="nx">age</span><span class="w"> </span><span class="kt">int</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-50-2"><a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a><span class="hll"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">age</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><span id="__span-50-3"><a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a><span class="hll"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Errorf</span><span class="p">(</span><span class="s">"age should be positive for customer %v"</span><span class="p">,</span><span class="w"> </span><span class="nx">c</span><span class="p">)</span>
|
||
</span></span><span id="__span-50-4"><a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="hll"><span class="w"> </span><span class="p">}</span>
|
||
</span></span><span id="__span-50-5"><a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a>
|
||
</span><span id="__span-50-6"><a id="__codelineno-50-6" name="__codelineno-50-6" href="#__codelineno-50-6"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span>
|
||
</span><span id="__span-50-7"><a id="__codelineno-50-7" name="__codelineno-50-7" href="#__codelineno-50-7"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
|
||
</span><span id="__span-50-8"><a id="__codelineno-50-8" name="__codelineno-50-8" href="#__codelineno-50-8"></a>
|
||
</span><span id="__span-50-9"><a id="__codelineno-50-9" name="__codelineno-50-9" href="#__codelineno-50-9"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">age</span>
|
||
</span><span id="__span-50-10"><a id="__codelineno-50-10" name="__codelineno-50-10" href="#__codelineno-50-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||
</span><span id="__span-50-11"><a id="__codelineno-50-11" name="__codelineno-50-11" href="#__codelineno-50-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Yet, such an approach isn't always possible. In these conditions, we have to be extremely careful with string formatting.</p>
|
||
<p>Another approach is to access the <code>id</code> field directly:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-51-1"><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Customer</span><span class="p">)</span><span class="w"> </span><span class="nx">UpdateAge</span><span class="p">(</span><span class="nx">age</span><span class="w"> </span><span class="kt">int</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-51-2"><a id="__codelineno-51-2" name="__codelineno-51-2" href="#__codelineno-51-2"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span>
|
||
</span><span id="__span-51-3"><a id="__codelineno-51-3" name="__codelineno-51-3" href="#__codelineno-51-3"></a><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mutex</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
|
||
</span><span id="__span-51-4"><a id="__codelineno-51-4" name="__codelineno-51-4" href="#__codelineno-51-4"></a>
|
||
</span><span id="__span-51-5"><a id="__codelineno-51-5" name="__codelineno-51-5" href="#__codelineno-51-5"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">age</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-51-6"><a id="__codelineno-51-6" name="__codelineno-51-6" href="#__codelineno-51-6"></a><span class="hll"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Errorf</span><span class="p">(</span><span class="s">"age should be positive for customer id %s"</span><span class="p">,</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span>
|
||
</span></span><span id="__span-51-7"><a id="__codelineno-51-7" name="__codelineno-51-7" href="#__codelineno-51-7"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-51-8"><a id="__codelineno-51-8" name="__codelineno-51-8" href="#__codelineno-51-8"></a>
|
||
</span><span id="__span-51-9"><a id="__codelineno-51-9" name="__codelineno-51-9" href="#__codelineno-51-9"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">age</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">age</span>
|
||
</span><span id="__span-51-10"><a id="__codelineno-51-10" name="__codelineno-51-10" href="#__codelineno-51-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span>
|
||
</span><span id="__span-51-11"><a id="__codelineno-51-11" name="__codelineno-51-11" href="#__codelineno-51-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>In concurrent applications, we should remain cautious about the possible side effects of string formatting.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/68-string-formatting/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="creating-data-races-with-append-69">Creating data races with append (#69)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Calling <code>append</code> isn’t always data-race-free; hence, it shouldn’t be used concurrently on a shared slice.</p>
|
||
</details>
|
||
<p>Should adding an element to a slice using <code>append</code> is data-race-free? Spoiler: it depends.</p>
|
||
<p>Do you believe this example has a data race? </p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-52-1"><a id="__codelineno-52-1" name="__codelineno-52-1" href="#__codelineno-52-1"></a><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-52-2"><a id="__codelineno-52-2" name="__codelineno-52-2" href="#__codelineno-52-2"></a>
|
||
</span><span id="__span-52-3"><a id="__codelineno-52-3" name="__codelineno-52-3" href="#__codelineno-52-3"></a><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// In a new goroutine, appends a new element on s</span>
|
||
</span><span id="__span-52-4"><a id="__codelineno-52-4" name="__codelineno-52-4" href="#__codelineno-52-4"></a><span class="w"> </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-52-5"><a id="__codelineno-52-5" name="__codelineno-52-5" href="#__codelineno-52-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">s1</span><span class="p">)</span>
|
||
</span><span id="__span-52-6"><a id="__codelineno-52-6" name="__codelineno-52-6" href="#__codelineno-52-6"></a><span class="p">}()</span>
|
||
</span><span id="__span-52-7"><a id="__codelineno-52-7" name="__codelineno-52-7" href="#__codelineno-52-7"></a>
|
||
</span><span id="__span-52-8"><a id="__codelineno-52-8" name="__codelineno-52-8" href="#__codelineno-52-8"></a><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// Same</span>
|
||
</span><span id="__span-52-9"><a id="__codelineno-52-9" name="__codelineno-52-9" href="#__codelineno-52-9"></a><span class="w"> </span><span class="nx">s2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-52-10"><a id="__codelineno-52-10" name="__codelineno-52-10" href="#__codelineno-52-10"></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">s2</span><span class="p">)</span>
|
||
</span><span id="__span-52-11"><a id="__codelineno-52-11" name="__codelineno-52-11" href="#__codelineno-52-11"></a><span class="p">}()</span>
|
||
</span></code></pre></div>
|
||
<p>The answer is no.</p>
|
||
<p>In this example, we create a slice with <code>make([]int, 1)</code>. The code creates a one-length, one-capacity slice. Thus, because the slice is full, using append in each goroutine returns a slice backed by a new array. It doesn’t mutate the existing array; hence, it doesn’t lead to a data race.</p>
|
||
<p>Now, let’s run the same example with a slight change in how we initialize <code>s</code>. Instead of creating a slice with a length of 1, we create it with a length of 0 but a capacity of 1. How about this new example? Does it contain a data race?</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-53-1"><a id="__codelineno-53-1" name="__codelineno-53-1" href="#__codelineno-53-1"></a><span class="hll"><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span></span><span id="__span-53-2"><a id="__codelineno-53-2" name="__codelineno-53-2" href="#__codelineno-53-2"></a>
|
||
</span><span id="__span-53-3"><a id="__codelineno-53-3" name="__codelineno-53-3" href="#__codelineno-53-3"></a><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span>
|
||
</span><span id="__span-53-4"><a id="__codelineno-53-4" name="__codelineno-53-4" href="#__codelineno-53-4"></a><span class="w"> </span><span class="nx">s1</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-53-5"><a id="__codelineno-53-5" name="__codelineno-53-5" href="#__codelineno-53-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">s1</span><span class="p">)</span>
|
||
</span><span id="__span-53-6"><a id="__codelineno-53-6" name="__codelineno-53-6" href="#__codelineno-53-6"></a><span class="p">}()</span>
|
||
</span><span id="__span-53-7"><a id="__codelineno-53-7" name="__codelineno-53-7" href="#__codelineno-53-7"></a>
|
||
</span><span id="__span-53-8"><a id="__codelineno-53-8" name="__codelineno-53-8" href="#__codelineno-53-8"></a><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-53-9"><a id="__codelineno-53-9" name="__codelineno-53-9" href="#__codelineno-53-9"></a><span class="w"> </span><span class="nx">s2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-53-10"><a id="__codelineno-53-10" name="__codelineno-53-10" href="#__codelineno-53-10"></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">s2</span><span class="p">)</span>
|
||
</span><span id="__span-53-11"><a id="__codelineno-53-11" name="__codelineno-53-11" href="#__codelineno-53-11"></a><span class="p">}()</span>
|
||
</span></code></pre></div>
|
||
<p>The answer is yes. We create a slice with <code>make([]int, 0, 1)</code>. Therefore, the array isn’t full. Both goroutines attempt to update the same index of the backing array (index 1), which is a data race.</p>
|
||
<p>How can we prevent the data race if we want both goroutines to work on a slice containing the initial elements of <code>s</code> plus an extra element? One solution is to create a copy of <code>s</code>.</p>
|
||
<p>We should remember that using append on a shared slice in concurrent applications can lead to a data race. Hence, it should be avoided.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/69-data-race-append/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="using-mutexes-inaccurately-with-slices-and-maps-70">Using mutexes inaccurately with slices and maps (#70)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Remembering that slices and maps are pointers can prevent common data races.</p>
|
||
</details>
|
||
<p>Let's implement a <code>Cache</code> struct used to handle caching for customer balances. This struct will contain a map of balances per customer ID and a mutex to protect concurrent accesses:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-54-1"><a id="__codelineno-54-1" name="__codelineno-54-1" href="#__codelineno-54-1"></a><span class="kd">type</span><span class="w"> </span><span class="nx">Cache</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-54-2"><a id="__codelineno-54-2" name="__codelineno-54-2" href="#__codelineno-54-2"></a><span class="w"> </span><span class="nx">mu</span><span class="w"> </span><span class="nx">sync</span><span class="p">.</span><span class="nx">RWMutex</span>
|
||
</span><span id="__span-54-3"><a id="__codelineno-54-3" name="__codelineno-54-3" href="#__codelineno-54-3"></a><span class="w"> </span><span class="nx">balances</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span>
|
||
</span><span id="__span-54-4"><a id="__codelineno-54-4" name="__codelineno-54-4" href="#__codelineno-54-4"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Next, we add an <code>AddBalance</code> method that mutates the <code>balances</code> map. The mutation is done in a critical section (within a mutex lock and a mutex unlock):</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-55-1"><a id="__codelineno-55-1" name="__codelineno-55-1" href="#__codelineno-55-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Cache</span><span class="p">)</span><span class="w"> </span><span class="nx">AddBalance</span><span class="p">(</span><span class="nx">id</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">balance</span><span class="w"> </span><span class="kt">float64</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-55-2"><a id="__codelineno-55-2" name="__codelineno-55-2" href="#__codelineno-55-2"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">Lock</span><span class="p">()</span>
|
||
</span><span id="__span-55-3"><a id="__codelineno-55-3" name="__codelineno-55-3" href="#__codelineno-55-3"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">balances</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">balance</span>
|
||
</span><span id="__span-55-4"><a id="__codelineno-55-4" name="__codelineno-55-4" href="#__codelineno-55-4"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">Unlock</span><span class="p">()</span>
|
||
</span><span id="__span-55-5"><a id="__codelineno-55-5" name="__codelineno-55-5" href="#__codelineno-55-5"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Meanwhile, we have to implement a method to calculate the average balance for all the customers. One idea is to handle a minimal critical section this way:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-56-1"><a id="__codelineno-56-1" name="__codelineno-56-1" href="#__codelineno-56-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Cache</span><span class="p">)</span><span class="w"> </span><span class="nx">AverageBalance</span><span class="p">()</span><span class="w"> </span><span class="kt">float64</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-56-2"><a id="__codelineno-56-2" name="__codelineno-56-2" href="#__codelineno-56-2"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RLock</span><span class="p">()</span>
|
||
</span><span id="__span-56-3"><a id="__codelineno-56-3" name="__codelineno-56-3" href="#__codelineno-56-3"></a><span class="w"> </span><span class="nx">balances</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">balances</span><span class="w"> </span><span class="c1">// Creates a copy of the balances map</span>
|
||
</span><span id="__span-56-4"><a id="__codelineno-56-4" name="__codelineno-56-4" href="#__codelineno-56-4"></a><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RUnlock</span><span class="p">()</span>
|
||
</span><span id="__span-56-5"><a id="__codelineno-56-5" name="__codelineno-56-5" href="#__codelineno-56-5"></a>
|
||
</span><span id="__span-56-6"><a id="__codelineno-56-6" name="__codelineno-56-6" href="#__codelineno-56-6"></a><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.</span>
|
||
</span><span id="__span-56-7"><a id="__codelineno-56-7" name="__codelineno-56-7" href="#__codelineno-56-7"></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">balance</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">balances</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// Iterates over the copy, outside of the critical section</span>
|
||
</span><span id="__span-56-8"><a id="__codelineno-56-8" name="__codelineno-56-8" href="#__codelineno-56-8"></a><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">balance</span>
|
||
</span><span id="__span-56-9"><a id="__codelineno-56-9" name="__codelineno-56-9" href="#__codelineno-56-9"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-56-10"><a id="__codelineno-56-10" name="__codelineno-56-10" href="#__codelineno-56-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">balances</span><span class="p">))</span>
|
||
</span><span id="__span-56-11"><a id="__codelineno-56-11" name="__codelineno-56-11" href="#__codelineno-56-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>What's the problem with this code?</p>
|
||
<p>If we run a test using the <code>-race</code> flag with two concurrent goroutines, one calling <code>AddBalance</code> (hence mutating balances) and another calling <code>AverageBalance</code>, a data race occurs. What’s the problem here?</p>
|
||
<p>Internally, a map is a <code>runtime.hmap</code> struct containing mostly metadata (for example, a counter) and a pointer referencing data buckets. So, <code>balances := c.balances</code> doesn’t copy the actual data. Therefore, the two goroutines perform operations on the same data set, and one mutates it. Hence, it's a data race.</p>
|
||
<p>One possible solution is to protect the whole <code>AverageBalance</code> function:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-57-1"><a id="__codelineno-57-1" name="__codelineno-57-1" href="#__codelineno-57-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Cache</span><span class="p">)</span><span class="w"> </span><span class="nx">AverageBalance</span><span class="p">()</span><span class="w"> </span><span class="kt">float64</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-57-2"><a id="__codelineno-57-2" name="__codelineno-57-2" href="#__codelineno-57-2"></a><span class="hll"><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RLock</span><span class="p">()</span>
|
||
</span></span><span id="__span-57-3"><a id="__codelineno-57-3" name="__codelineno-57-3" href="#__codelineno-57-3"></a><span class="hll"><span class="w"> </span><span class="k">defer</span><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RUnlock</span><span class="p">()</span><span class="w"> </span><span class="c1">// Unlocks when the function returns</span>
|
||
</span></span><span id="__span-57-4"><a id="__codelineno-57-4" name="__codelineno-57-4" href="#__codelineno-57-4"></a>
|
||
</span><span id="__span-57-5"><a id="__codelineno-57-5" name="__codelineno-57-5" href="#__codelineno-57-5"></a><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.</span>
|
||
</span><span id="__span-57-6"><a id="__codelineno-57-6" name="__codelineno-57-6" href="#__codelineno-57-6"></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">balance</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">c</span><span class="p">.</span><span class="nx">balances</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-57-7"><a id="__codelineno-57-7" name="__codelineno-57-7" href="#__codelineno-57-7"></a><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">balance</span>
|
||
</span><span id="__span-57-8"><a id="__codelineno-57-8" name="__codelineno-57-8" href="#__codelineno-57-8"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-57-9"><a id="__codelineno-57-9" name="__codelineno-57-9" href="#__codelineno-57-9"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">balances</span><span class="p">))</span>
|
||
</span><span id="__span-57-10"><a id="__codelineno-57-10" name="__codelineno-57-10" href="#__codelineno-57-10"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Another option, if the iteration operation isn’t lightweight, is to work on an actual copy of the data and protect only the copy:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-58-1"><a id="__codelineno-58-1" name="__codelineno-58-1" href="#__codelineno-58-1"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">c</span><span class="w"> </span><span class="o">*</span><span class="nx">Cache</span><span class="p">)</span><span class="w"> </span><span class="nx">AverageBalance</span><span class="p">()</span><span class="w"> </span><span class="kt">float64</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-58-2"><a id="__codelineno-58-2" name="__codelineno-58-2" href="#__codelineno-58-2"></a><span class="hll"><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RLock</span><span class="p">()</span>
|
||
</span></span><span id="__span-58-3"><a id="__codelineno-58-3" name="__codelineno-58-3" href="#__codelineno-58-3"></a><span class="hll"><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">maps</span><span class="p">.</span><span class="nx">Clone</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">balances</span><span class="p">)</span>
|
||
</span></span><span id="__span-58-4"><a id="__codelineno-58-4" name="__codelineno-58-4" href="#__codelineno-58-4"></a><span class="hll"><span class="w"> </span><span class="nx">c</span><span class="p">.</span><span class="nx">mu</span><span class="p">.</span><span class="nx">RUnlock</span><span class="p">()</span>
|
||
</span></span><span id="__span-58-5"><a id="__codelineno-58-5" name="__codelineno-58-5" href="#__codelineno-58-5"></a><span class="hll">
|
||
</span></span><span id="__span-58-6"><a id="__codelineno-58-6" name="__codelineno-58-6" href="#__codelineno-58-6"></a><span class="hll"><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.</span>
|
||
</span></span><span id="__span-58-7"><a id="__codelineno-58-7" name="__codelineno-58-7" href="#__codelineno-58-7"></a><span class="hll"><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">balance</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">m</span><span class="w"> </span><span class="p">{</span>
|
||
</span></span><span id="__span-58-8"><a id="__codelineno-58-8" name="__codelineno-58-8" href="#__codelineno-58-8"></a><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">balance</span>
|
||
</span><span id="__span-58-9"><a id="__codelineno-58-9" name="__codelineno-58-9" href="#__codelineno-58-9"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-58-10"><a id="__codelineno-58-10" name="__codelineno-58-10" href="#__codelineno-58-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="nx">m</span><span class="p">))</span>
|
||
</span><span id="__span-58-11"><a id="__codelineno-58-11" name="__codelineno-58-11" href="#__codelineno-58-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Once we have made a deep copy, we release the mutex. The iterations are done on the copy outside of the critical section.</p>
|
||
<p>In summary, we have to be careful with the boundaries of a mutex lock. In this section, we have seen why assigning an existing map (or an existing slice) to a map isn’t enough to protect against data races. The new variable, whether a map or a slice, is backed by the same data set. There are two leading solutions to prevent this: protect the whole function, or work on a copy of the actual data. In all cases, let’s be cautious when designing critical sections and make sure the boundaries are accurately defined.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/70-mutex-slices-maps/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="misusing-syncwaitgroup-71">Misusing <code>sync.WaitGroup</code> (#71)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To accurately use <code>sync.WaitGroup</code>, call the <code>Add</code> method before spinning up goroutines.</p>
|
||
</details>
|
||
<p>In the following example, we will initialize a wait group, start three goroutines that will update a counter atomically, and then wait for them to complete. We want to wait for these three goroutines to print the value of the counter (which should be 3):</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-59-1"><a id="__codelineno-59-1" name="__codelineno-59-1" href="#__codelineno-59-1"></a><span class="nx">wg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span>
|
||
</span><span id="__span-59-2"><a id="__codelineno-59-2" name="__codelineno-59-2" href="#__codelineno-59-2"></a><span class="kd">var</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="kt">uint64</span>
|
||
</span><span id="__span-59-3"><a id="__codelineno-59-3" name="__codelineno-59-3" href="#__codelineno-59-3"></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">3</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-59-4"><a id="__codelineno-59-4" name="__codelineno-59-4" href="#__codelineno-59-4"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-59-5"><a id="__codelineno-59-5" name="__codelineno-59-5" href="#__codelineno-59-5"></a><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nx">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-59-6"><a id="__codelineno-59-6" name="__codelineno-59-6" href="#__codelineno-59-6"></a><span class="w"> </span><span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-59-7"><a id="__codelineno-59-7" name="__codelineno-59-7" href="#__codelineno-59-7"></a><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nx">Done</span><span class="p">()</span>
|
||
</span><span id="__span-59-8"><a id="__codelineno-59-8" name="__codelineno-59-8" href="#__codelineno-59-8"></a><span class="w"> </span><span class="p">}()</span>
|
||
</span><span id="__span-59-9"><a id="__codelineno-59-9" name="__codelineno-59-9" href="#__codelineno-59-9"></a><span class="p">}</span>
|
||
</span><span id="__span-59-10"><a id="__codelineno-59-10" name="__codelineno-59-10" href="#__codelineno-59-10"></a><span class="nx">wg</span><span class="p">.</span><span class="nx">Wait</span><span class="p">()</span>
|
||
</span><span id="__span-59-11"><a id="__codelineno-59-11" name="__codelineno-59-11" href="#__codelineno-59-11"></a><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></code></pre></div>
|
||
<p>If we run this example, we get a non-deterministic value: the code can print any value from 0 to 3. Also, if we enable the <code>-race</code> flag, Go will even catch a data race.</p>
|
||
<p>The problem is that <code>wg.Add(1)</code> is called within the newly created goroutine, not in the parent goroutine. Hence, there is no guarantee that we have indicated to the wait group that we want to wait for three goroutines before calling <code>wg.Wait()</code>.</p>
|
||
<p>To fix this issue, we can call <code>wg.Add</code> before the loop:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-60-1"><a id="__codelineno-60-1" name="__codelineno-60-1" href="#__codelineno-60-1"></a><span class="nx">wg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span>
|
||
</span><span id="__span-60-2"><a id="__codelineno-60-2" name="__codelineno-60-2" href="#__codelineno-60-2"></a><span class="kd">var</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="kt">uint64</span>
|
||
</span><span id="__span-60-3"><a id="__codelineno-60-3" name="__codelineno-60-3" href="#__codelineno-60-3"></a><span class="nx">wg</span><span class="p">.</span><span class="nx">Add</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
|
||
</span><span id="__span-60-4"><a id="__codelineno-60-4" name="__codelineno-60-4" href="#__codelineno-60-4"></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">3</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-60-5"><a id="__codelineno-60-5" name="__codelineno-60-5" href="#__codelineno-60-5"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-60-6"><a id="__codelineno-60-6" name="__codelineno-60-6" href="#__codelineno-60-6"></a><span class="w"> </span><span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-60-7"><a id="__codelineno-60-7" name="__codelineno-60-7" href="#__codelineno-60-7"></a><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nx">Done</span><span class="p">()</span>
|
||
</span><span id="__span-60-8"><a id="__codelineno-60-8" name="__codelineno-60-8" href="#__codelineno-60-8"></a><span class="w"> </span><span class="p">}()</span>
|
||
</span><span id="__span-60-9"><a id="__codelineno-60-9" name="__codelineno-60-9" href="#__codelineno-60-9"></a><span class="p">}</span>
|
||
</span><span id="__span-60-10"><a id="__codelineno-60-10" name="__codelineno-60-10" href="#__codelineno-60-10"></a><span class="nx">wg</span><span class="p">.</span><span class="nx">Wait</span><span class="p">()</span>
|
||
</span><span id="__span-60-11"><a id="__codelineno-60-11" name="__codelineno-60-11" href="#__codelineno-60-11"></a><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></code></pre></div>
|
||
<p>Or inside the loop but not in the newly created goroutine:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-61-1"><a id="__codelineno-61-1" name="__codelineno-61-1" href="#__codelineno-61-1"></a><span class="nx">wg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span><span class="p">{}</span>
|
||
</span><span id="__span-61-2"><a id="__codelineno-61-2" name="__codelineno-61-2" href="#__codelineno-61-2"></a><span class="kd">var</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="kt">uint64</span>
|
||
</span><span id="__span-61-3"><a id="__codelineno-61-3" name="__codelineno-61-3" href="#__codelineno-61-3"></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">3</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-61-4"><a id="__codelineno-61-4" name="__codelineno-61-4" href="#__codelineno-61-4"></a><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nx">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-61-5"><a id="__codelineno-61-5" name="__codelineno-61-5" href="#__codelineno-61-5"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-61-6"><a id="__codelineno-61-6" name="__codelineno-61-6" href="#__codelineno-61-6"></a><span class="w"> </span><span class="nx">atomic</span><span class="p">.</span><span class="nx">AddUint64</span><span class="p">(</span><span class="o">&</span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span>
|
||
</span><span id="__span-61-7"><a id="__codelineno-61-7" name="__codelineno-61-7" href="#__codelineno-61-7"></a><span class="w"> </span><span class="nx">wg</span><span class="p">.</span><span class="nx">Done</span><span class="p">()</span>
|
||
</span><span id="__span-61-8"><a id="__codelineno-61-8" name="__codelineno-61-8" href="#__codelineno-61-8"></a><span class="w"> </span><span class="p">}()</span>
|
||
</span><span id="__span-61-9"><a id="__codelineno-61-9" name="__codelineno-61-9" href="#__codelineno-61-9"></a><span class="p">}</span>
|
||
</span><span id="__span-61-10"><a id="__codelineno-61-10" name="__codelineno-61-10" href="#__codelineno-61-10"></a><span class="nx">wg</span><span class="p">.</span><span class="nx">Wait</span><span class="p">()</span>
|
||
</span><span id="__span-61-11"><a id="__codelineno-61-11" name="__codelineno-61-11" href="#__codelineno-61-11"></a><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></code></pre></div>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/71-wait-group/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="forgetting-about-synccond-72">Forgetting about <code>sync.Cond</code> (#72)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>You can send repeated notifications to multiple goroutines with <code>sync.Cond</code>.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/72-cond/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-using-errgroup-73">Not using <code>errgroup</code> (#73)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>You can synchronize a group of goroutines and handle errors and contexts with the <code>errgroup</code> package.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/73-errgroup/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="copying-a-sync-type-74">Copying a <code>sync</code> type (#74)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p><code>sync</code> types shouldn’t be copied.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/09-concurrency-practice/74-copying-sync/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="standard-library">Standard Library</h2>
|
||
<h3 id="providing-a-wrong-time-duration-75">Providing a wrong time duration (#75)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Remain cautious with functions accepting a <code>time.Duration</code>. Even though passing an integer is allowed, strive to use the time API to prevent any possible confusion.</p>
|
||
</details>
|
||
<p>Many common functions in the standard library accept a <code>time.Duration</code>, which is an alias for the <code>int64</code> type. However, one <code>time.Duration</code> unit represents one nanosecond, instead of one millisecond, as commonly seen in other programming languages. As a result, passing numeric types instead of using the <code>time.Duration</code> API can lead to unexpected behavior.</p>
|
||
<p>A developer with experience in other languages might assume that the following code creates a new <code>time.Ticker</code> that delivers ticks every second, given the value <code>1000</code>:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-62-1"><a id="__codelineno-62-1" name="__codelineno-62-1" href="#__codelineno-62-1"></a><span class="nx">ticker</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">NewTicker</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
|
||
</span><span id="__span-62-2"><a id="__codelineno-62-2" name="__codelineno-62-2" href="#__codelineno-62-2"></a><span class="k">for</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-62-3"><a id="__codelineno-62-3" name="__codelineno-62-3" href="#__codelineno-62-3"></a><span class="w"> </span><span class="k">select</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-62-4"><a id="__codelineno-62-4" name="__codelineno-62-4" href="#__codelineno-62-4"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="o"><-</span><span class="nx">ticker</span><span class="p">.</span><span class="nx">C</span><span class="p">:</span>
|
||
</span><span id="__span-62-5"><a id="__codelineno-62-5" name="__codelineno-62-5" href="#__codelineno-62-5"></a><span class="w"> </span><span class="c1">// Do something</span>
|
||
</span><span id="__span-62-6"><a id="__codelineno-62-6" name="__codelineno-62-6" href="#__codelineno-62-6"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-62-7"><a id="__codelineno-62-7" name="__codelineno-62-7" href="#__codelineno-62-7"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>However, because 1,000 <code>time.Duration</code> units = 1,000 nanoseconds, ticks are delivered every 1,000 nanoseconds = 1 microsecond, not every second as assumed.</p>
|
||
<p>We should always use the <code>time.Duration</code> API to avoid confusion and unexpected behavior:
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-63-1"><a id="__codelineno-63-1" name="__codelineno-63-1" href="#__codelineno-63-1"></a><span class="nx">ticker</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">NewTicker</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Microsecond</span><span class="p">)</span>
|
||
</span><span id="__span-63-2"><a id="__codelineno-63-2" name="__codelineno-63-2" href="#__codelineno-63-2"></a><span class="c1">// Or</span>
|
||
</span><span id="__span-63-3"><a id="__codelineno-63-3" name="__codelineno-63-3" href="#__codelineno-63-3"></a><span class="nx">ticker</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">NewTicker</span><span class="p">(</span><span class="mi">1000</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Nanosecond</span><span class="p">)</span>
|
||
</span></code></pre></div></p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/75-wrong-time-duration/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="timeafter-and-memory-leaks-76"><code>time.After</code> and memory leaks (#76)</h3>
|
||
<details class="warning" open="open">
|
||
<summary>Warning</summary>
|
||
<p>This mistake isn't relevant anymore from Go 1.23 (<a href="https://go.dev/wiki/Go123Timer">details</a>).</p>
|
||
</details>
|
||
<h3 id="json-handling-common-mistakes-77">JSON handling common mistakes (#77)</h3>
|
||
<ul>
|
||
<li>Unexpected behavior because of type embedding</li>
|
||
</ul>
|
||
<p>Be careful about using embedded fields in Go structs. Doing so may lead to sneaky bugs like an embedded time.Time field implementing the <code>json.Marshaler</code> interface, hence overriding the default marshaling behavior.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/77-json-handling/type-embedding/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>JSON and the monotonic clock</li>
|
||
</ul>
|
||
<p>When comparing two <code>time.Time</code> structs, recall that <code>time.Time</code> contains both a wall clock and a monotonic clock, and the comparison using the == operator is done on both clocks.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/77-json-handling/monotonic-clock/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Map of <code>any</code></li>
|
||
</ul>
|
||
<p>To avoid wrong assumptions when you provide a map while unmarshaling JSON data, remember that numerics are converted to <code>float64</code> by default.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/77-json-handling/map-any/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="common-sql-mistakes-78">Common SQL mistakes (#78)</h3>
|
||
<ul>
|
||
<li>Forgetting that <code>sql.Open</code> doesn't necessarily establish connections to a database</li>
|
||
</ul>
|
||
<p>Call the <code>Ping</code> or <code>PingContext</code> method if you need to test your configuration and make sure a database is reachable.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/78-sql/sql-open"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Forgetting about connections pooling</li>
|
||
</ul>
|
||
<p>Configure the database connection parameters for production-grade applications.</p>
|
||
<ul>
|
||
<li>Not using prepared statements</li>
|
||
</ul>
|
||
<p>Using SQL prepared statements makes queries more efficient and more secure.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/78-sql/prepared-statements"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Mishandling null values</li>
|
||
</ul>
|
||
<p>Deal with nullable columns in tables using pointers or <code>sql.NullXXX</code> types.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/78-sql/null-values/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Not handling rows iteration errors</li>
|
||
</ul>
|
||
<p>Call the <code>Err</code> method of <code>sql.Rows</code> after row iterations to ensure that you haven’t missed an error while preparing the next row.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/78-sql/rows-iterations-errors"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-closing-transient-resources-http-body-sqlrows-and-osfile-79">Not closing transient resources (HTTP body, <code>sql.Rows</code>, and <code>os.File</code>) (#79)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Eventually close all structs implementing <code>io.Closer</code> to avoid possible leaks.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/79-closing-resources/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="forgetting-the-return-statement-after-replying-to-an-http-request-80">Forgetting the return statement after replying to an HTTP request (#80)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To avoid unexpected behaviors in HTTP handler implementations, make sure you don’t miss the <code>return</code> statement if you want a handler to stop after <code>http.Error</code>.</p>
|
||
</details>
|
||
<p>Consider the following HTTP handler that handles an error from <code>foo</code> using <code>http.Error</code>:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-64-1"><a id="__codelineno-64-1" name="__codelineno-64-1" href="#__codelineno-64-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">handler</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">req</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-64-2"><a id="__codelineno-64-2" name="__codelineno-64-2" href="#__codelineno-64-2"></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">foo</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span>
|
||
</span><span id="__span-64-3"><a id="__codelineno-64-3" name="__codelineno-64-3" href="#__codelineno-64-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="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-64-4"><a id="__codelineno-64-4" name="__codelineno-64-4" href="#__codelineno-64-4"></a><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">"foo"</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusInternalServerError</span><span class="p">)</span>
|
||
</span><span id="__span-64-5"><a id="__codelineno-64-5" name="__codelineno-64-5" href="#__codelineno-64-5"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-64-6"><a id="__codelineno-64-6" name="__codelineno-64-6" href="#__codelineno-64-6"></a>
|
||
</span><span id="__span-64-7"><a id="__codelineno-64-7" name="__codelineno-64-7" href="#__codelineno-64-7"></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">w</span><span class="p">.</span><span class="nx">Write</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">"all good"</span><span class="p">))</span>
|
||
</span><span id="__span-64-8"><a id="__codelineno-64-8" name="__codelineno-64-8" href="#__codelineno-64-8"></a><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nx">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusCreated</span><span class="p">)</span>
|
||
</span><span id="__span-64-9"><a id="__codelineno-64-9" name="__codelineno-64-9" href="#__codelineno-64-9"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>If we run this code and <code>err != nil</code>, the HTTP response would be:</p>
|
||
<div class="language-text highlight"><pre><span></span><code><span id="__span-65-1"><a id="__codelineno-65-1" name="__codelineno-65-1" href="#__codelineno-65-1"></a>foo
|
||
</span><span id="__span-65-2"><a id="__codelineno-65-2" name="__codelineno-65-2" href="#__codelineno-65-2"></a>all good
|
||
</span></code></pre></div>
|
||
<p>The response contains both the error and success messages, and also the first HTTP status code, 500. There would also be a warning log indicating that we attempted to write the status code multiple times:</p>
|
||
<div class="language-text highlight"><pre><span></span><code><span id="__span-66-1"><a id="__codelineno-66-1" name="__codelineno-66-1" href="#__codelineno-66-1"></a>2023/10/10 16:45:33 http: superfluous response.WriteHeader call from main.handler (main.go:20)
|
||
</span></code></pre></div>
|
||
<p>The mistake in this code is that <code>http.Error</code> does not stop the handler's execution, which means the success message and status code get written in addition to the error. Beyond an incorrect response, failing to return after writing an error can lead to the unwanted execution of code and unexpected side-effects. The following code adds the <code>return</code> statement following the <code>http.Error</code> and exhibits the desired behavior when ran:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-67-1"><a id="__codelineno-67-1" name="__codelineno-67-1" href="#__codelineno-67-1"></a><span class="kd">func</span><span class="w"> </span><span class="nx">handler</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">req</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-67-2"><a id="__codelineno-67-2" name="__codelineno-67-2" href="#__codelineno-67-2"></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">foo</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span>
|
||
</span><span id="__span-67-3"><a id="__codelineno-67-3" name="__codelineno-67-3" href="#__codelineno-67-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="kc">nil</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-67-4"><a id="__codelineno-67-4" name="__codelineno-67-4" href="#__codelineno-67-4"></a><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">"foo"</span><span class="p">,</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusInternalServerError</span><span class="p">)</span>
|
||
</span><span id="__span-67-5"><a id="__codelineno-67-5" name="__codelineno-67-5" href="#__codelineno-67-5"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="c1">// Adds the return statement</span>
|
||
</span><span id="__span-67-6"><a id="__codelineno-67-6" name="__codelineno-67-6" href="#__codelineno-67-6"></a><span class="w"> </span><span class="p">}</span>
|
||
</span><span id="__span-67-7"><a id="__codelineno-67-7" name="__codelineno-67-7" href="#__codelineno-67-7"></a>
|
||
</span><span id="__span-67-8"><a id="__codelineno-67-8" name="__codelineno-67-8" href="#__codelineno-67-8"></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">w</span><span class="p">.</span><span class="nx">Write</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">"all good"</span><span class="p">))</span>
|
||
</span><span id="__span-67-9"><a id="__codelineno-67-9" name="__codelineno-67-9" href="#__codelineno-67-9"></a><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nx">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusCreated</span><span class="p">)</span>
|
||
</span><span id="__span-67-10"><a id="__codelineno-67-10" name="__codelineno-67-10" href="#__codelineno-67-10"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/80-http-return/main.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="using-the-default-http-client-and-server-81">Using the default HTTP client and server (#81)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>For production-grade applications, don’t use the default HTTP client and server implementations. These implementations are missing timeouts and behaviors that should be mandatory in production.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/81-default-http-client-server/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h2 id="testing">Testing</h2>
|
||
<h3 id="not-categorizing-tests-build-tags-environment-variables-and-short-mode-82">Not categorizing tests (build tags, environment variables, and short mode) (#82)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Categorizing tests using build flags, environment variables, or short mode makes the testing process more efficient. You can create test categories using build flags or environment variables (for example, unit versus integration tests) and differentiate short from long-running tests to decide which kinds of tests to execute.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/82-categorizing-tests/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-enabling-the-race-flag-83">Not enabling the race flag (#83)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Enabling the <code>-race</code> flag is highly recommended when writing concurrent applications. Doing so allows you to catch potential data races that can lead to software bugs.</p>
|
||
</details>
|
||
<p>In Go, the race detector isn’t a static analysis tool used during compilation; instead, it’s a tool to find data races that occur at runtime. To enable it, we have to enable the -race flag while compiling or running a test. For example:</p>
|
||
<div class="language-bash highlight"><pre><span></span><code><span id="__span-68-1"><a id="__codelineno-68-1" name="__codelineno-68-1" href="#__codelineno-68-1"></a>go<span class="w"> </span><span class="nb">test</span><span class="w"> </span>-race<span class="w"> </span>./...
|
||
</span></code></pre></div>
|
||
<p>Once the race detector is enabled, the compiler instruments the code to detect data races. Instrumentation refers to a compiler adding extra instructions: here, tracking all memory accesses and recording when and how they occur.</p>
|
||
<p>Enabling the race detector adds an overhead in terms of memory and execution time; hence, it's generally recommended to enable it only during local testing or continuous integration, not production.</p>
|
||
<p>If a race is detected, Go raises a warning. For example:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-69-1"><a id="__codelineno-69-1" name="__codelineno-69-1" href="#__codelineno-69-1"></a><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>
|
||
</span><span id="__span-69-2"><a id="__codelineno-69-2" name="__codelineno-69-2" href="#__codelineno-69-2"></a>
|
||
</span><span id="__span-69-3"><a id="__codelineno-69-3" name="__codelineno-69-3" href="#__codelineno-69-3"></a><span class="kn">import</span><span class="w"> </span><span class="p">(</span>
|
||
</span><span id="__span-69-4"><a id="__codelineno-69-4" name="__codelineno-69-4" href="#__codelineno-69-4"></a><span class="w"> </span><span class="s">"fmt"</span>
|
||
</span><span id="__span-69-5"><a id="__codelineno-69-5" name="__codelineno-69-5" href="#__codelineno-69-5"></a><span class="p">)</span>
|
||
</span><span id="__span-69-6"><a id="__codelineno-69-6" name="__codelineno-69-6" href="#__codelineno-69-6"></a>
|
||
</span><span id="__span-69-7"><a id="__codelineno-69-7" name="__codelineno-69-7" href="#__codelineno-69-7"></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-69-8"><a id="__codelineno-69-8" name="__codelineno-69-8" href="#__codelineno-69-8"></a><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><span id="__span-69-9"><a id="__codelineno-69-9" name="__codelineno-69-9" href="#__codelineno-69-9"></a><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="kd">func</span><span class="p">()</span><span class="w"> </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-69-10"><a id="__codelineno-69-10" name="__codelineno-69-10" href="#__codelineno-69-10"></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">i</span><span class="p">)</span>
|
||
</span><span id="__span-69-11"><a id="__codelineno-69-11" name="__codelineno-69-11" href="#__codelineno-69-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<p>Running this code with the <code>-race</code> logs the following warning:</p>
|
||
<div class="language-bash highlight"><pre><span></span><code><span id="__span-70-1"><a id="__codelineno-70-1" name="__codelineno-70-1" href="#__codelineno-70-1"></a><span class="o">==================</span>
|
||
</span><span id="__span-70-2"><a id="__codelineno-70-2" name="__codelineno-70-2" href="#__codelineno-70-2"></a>WARNING:<span class="w"> </span>DATA<span class="w"> </span>RACE
|
||
</span><span id="__span-70-3"><a id="__codelineno-70-3" name="__codelineno-70-3" href="#__codelineno-70-3"></a><span class="hll">Write<span class="w"> </span>at<span class="w"> </span>0x00c000026078<span class="w"> </span>by<span class="w"> </span>goroutine<span class="w"> </span><span class="m">7</span>:<span class="w"> </span><span class="c1"># (1)</span>
|
||
</span></span><span id="__span-70-4"><a id="__codelineno-70-4" name="__codelineno-70-4" href="#__codelineno-70-4"></a><span class="w"> </span>main.main.func1<span class="o">()</span>
|
||
</span><span id="__span-70-5"><a id="__codelineno-70-5" name="__codelineno-70-5" href="#__codelineno-70-5"></a><span class="w"> </span>/tmp/app/main.go:9<span class="w"> </span>+0x4e
|
||
</span><span id="__span-70-6"><a id="__codelineno-70-6" name="__codelineno-70-6" href="#__codelineno-70-6"></a>
|
||
</span><span id="__span-70-7"><a id="__codelineno-70-7" name="__codelineno-70-7" href="#__codelineno-70-7"></a><span class="hll">Previous<span class="w"> </span><span class="nb">read</span><span class="w"> </span>at<span class="w"> </span>0x00c000026078<span class="w"> </span>by<span class="w"> </span>main<span class="w"> </span>goroutine:<span class="w"> </span><span class="c1"># (2)</span>
|
||
</span></span><span id="__span-70-8"><a id="__codelineno-70-8" name="__codelineno-70-8" href="#__codelineno-70-8"></a><span class="w"> </span>main.main<span class="o">()</span>
|
||
</span><span id="__span-70-9"><a id="__codelineno-70-9" name="__codelineno-70-9" href="#__codelineno-70-9"></a><span class="w"> </span>/tmp/app/main.go:10<span class="w"> </span>+0x88
|
||
</span><span id="__span-70-10"><a id="__codelineno-70-10" name="__codelineno-70-10" href="#__codelineno-70-10"></a>
|
||
</span><span id="__span-70-11"><a id="__codelineno-70-11" name="__codelineno-70-11" href="#__codelineno-70-11"></a><span class="hll">Goroutine<span class="w"> </span><span class="m">7</span><span class="w"> </span><span class="o">(</span>running<span class="o">)</span><span class="w"> </span>created<span class="w"> </span>at:<span class="w"> </span><span class="c1"># (3)</span>
|
||
</span></span><span id="__span-70-12"><a id="__codelineno-70-12" name="__codelineno-70-12" href="#__codelineno-70-12"></a><span class="w"> </span>main.main<span class="o">()</span>
|
||
</span><span id="__span-70-13"><a id="__codelineno-70-13" name="__codelineno-70-13" href="#__codelineno-70-13"></a><span class="w"> </span>/tmp/app/main.go:9<span class="w"> </span>+0x7a
|
||
</span><span id="__span-70-14"><a id="__codelineno-70-14" name="__codelineno-70-14" href="#__codelineno-70-14"></a><span class="o">==================</span>
|
||
</span></code></pre></div>
|
||
<ol>
|
||
<li>Indicates that goroutine 7 was writing</li>
|
||
<li>Indicates that the main goroutine was reading</li>
|
||
<li>Indicates when the goroutine 7 was created</li>
|
||
</ol>
|
||
<p>Let’s make sure we are comfortable reading these messages. Go always logs the following:</p>
|
||
<ul>
|
||
<li>The concurrent goroutines that are incriminated: here, the main goroutine and goroutine 7.</li>
|
||
<li>Where accesses occur in the code: in this case, lines 9 and 10.</li>
|
||
<li>When these goroutines were created: goroutine 7 was created in main().</li>
|
||
</ul>
|
||
<p>In addition, if a specific file contains tests that lead to data races, we can exclude it <span class="twemoji" title="temporarily! 😉"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11 9h2V7h-2m1 13c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2m-1 15h2v-6h-2v6Z"/></svg></span> from race detection using the <code>!race</code> build tag:</p>
|
||
<div class="language-go highlight"><pre><span></span><code><span id="__span-71-1"><a id="__codelineno-71-1" name="__codelineno-71-1" href="#__codelineno-71-1"></a><span class="c1">//go:build !race</span>
|
||
</span><span id="__span-71-2"><a id="__codelineno-71-2" name="__codelineno-71-2" href="#__codelineno-71-2"></a>
|
||
</span><span id="__span-71-3"><a id="__codelineno-71-3" name="__codelineno-71-3" href="#__codelineno-71-3"></a><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>
|
||
</span><span id="__span-71-4"><a id="__codelineno-71-4" name="__codelineno-71-4" href="#__codelineno-71-4"></a>
|
||
</span><span id="__span-71-5"><a id="__codelineno-71-5" name="__codelineno-71-5" href="#__codelineno-71-5"></a><span class="kn">import</span><span class="w"> </span><span class="p">(</span>
|
||
</span><span id="__span-71-6"><a id="__codelineno-71-6" name="__codelineno-71-6" href="#__codelineno-71-6"></a><span class="w"> </span><span class="s">"testing"</span>
|
||
</span><span id="__span-71-7"><a id="__codelineno-71-7" name="__codelineno-71-7" href="#__codelineno-71-7"></a><span class="p">)</span>
|
||
</span><span id="__span-71-8"><a id="__codelineno-71-8" name="__codelineno-71-8" href="#__codelineno-71-8"></a>
|
||
</span><span id="__span-71-9"><a id="__codelineno-71-9" name="__codelineno-71-9" href="#__codelineno-71-9"></a><span class="kd">func</span><span class="w"> </span><span class="nx">TestFoo</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
</span><span id="__span-71-10"><a id="__codelineno-71-10" name="__codelineno-71-10" href="#__codelineno-71-10"></a><span class="w"> </span><span class="c1">// ...</span>
|
||
</span><span id="__span-71-11"><a id="__codelineno-71-11" name="__codelineno-71-11" href="#__codelineno-71-11"></a><span class="p">}</span>
|
||
</span></code></pre></div>
|
||
<h3 id="not-using-test-execution-modes-parallel-and-shuffle-84">Not using test execution modes (parallel and shuffle) (#84)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Using the <code>-parallel</code> flag is an efficient way to speed up tests, especially long-running ones. Use the <code>-shuffle</code> flag to help ensure that a test suite doesn’t rely on wrong assumptions that could hide bugs.</p>
|
||
</details>
|
||
<h3 id="not-using-table-driven-tests-85">Not using table-driven tests (#85)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Table-driven tests are an efficient way to group a set of similar tests to prevent code duplication and make future updates easier to handle.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/85-table-driven-tests/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="sleeping-in-unit-tests-86">Sleeping in unit tests (#86)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Avoid sleeps using synchronization to make a test less flaky and more robust. If synchronization isn’t possible, consider a retry approach.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/86-sleeping/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-dealing-with-the-time-api-efficiently-87">Not dealing with the time API efficiently (#87)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding how to deal with functions using the time API is another way to make a test less flaky. You can use standard techniques such as handling the time as part of a hidden dependency or asking clients to provide it.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/87-time-api/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-using-testing-utility-packages-httptest-and-iotest-88">Not using testing utility packages (<code>httptest</code> and <code>iotest</code>) (#88)</h3>
|
||
<ul>
|
||
<li>The <code>httptest</code> package is helpful for dealing with HTTP applications. It provides a set of utilities to test both clients and servers.</li>
|
||
</ul>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/88-utility-package/httptest/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>The <code>iotest</code> package helps write io.Reader and test that an application is tolerant to errors.</li>
|
||
</ul>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/88-utility-package/iotest/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="writing-inaccurate-benchmarks-89">Writing inaccurate benchmarks (#89)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Regarding benchmarks:</p>
|
||
<ul>
|
||
<li>Use time methods to preserve the accuracy of a benchmark.</li>
|
||
<li>Increasing benchtime or using tools such as benchstat can be helpful when dealing with micro-benchmarks.</li>
|
||
<li>Be careful with the results of a micro-benchmark if the system that ends up running the application is different from the one running the micro-benchmark.</li>
|
||
<li>Make sure the function under test leads to a side effect, to prevent compiler optimizations from fooling you about the benchmark results.</li>
|
||
<li>To prevent the observer effect, force a benchmark to re-create the data used by a CPU-bound function.</li>
|
||
</ul>
|
||
</details>
|
||
<p>Read the full section <a href="89-benchmarks/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/89-benchmark/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-exploring-all-the-go-testing-features-90">Not exploring all the Go testing features (#90)</h3>
|
||
<ul>
|
||
<li>Code coverage</li>
|
||
</ul>
|
||
<p>Use code coverage with the <code>-coverprofile</code> flag to quickly see which part of the code needs more attention.</p>
|
||
<ul>
|
||
<li>Testing from a different package</li>
|
||
</ul>
|
||
<p>Place unit tests in a different package to enforce writing tests that focus on an exposed behavior, not internals.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/90-testing-features/different-package/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Utility functions</li>
|
||
</ul>
|
||
<p>Handling errors using the <code>*testing.T</code> variable instead of the classic <code>if err != nil</code> makes code shorter and easier to read.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/90-testing-features/utility-function/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Setup and teardown</li>
|
||
</ul>
|
||
<p>You can use setup and teardown functions to configure a complex environment, such as in the case of integration tests.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/11-testing/90-testing-features/setup-teardown/main_test.go"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-using-fuzzing-community-mistake">Not using fuzzing (community mistake)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Fuzzing is an efficient strategy to detect random, unexpected, or malformed inputs to complex functions and methods in order to discover vulnerabilities, bugs, or even potential crashes.</p>
|
||
</details>
|
||
<p>Credits: <a href="https://github.com/jeromedoucet">@jeromedoucet</a></p>
|
||
<h2 id="optimizations">Optimizations</h2>
|
||
<h3 id="not-understanding-cpu-caches-91">Not understanding CPU caches (#91)</h3>
|
||
<ul>
|
||
<li>CPU architecture</li>
|
||
</ul>
|
||
<p>Understanding how to use CPU caches is important for optimizing CPU-bound applications because the L1 cache is about 50 to 100 times faster than the main memory.</p>
|
||
<ul>
|
||
<li>Cache line</li>
|
||
</ul>
|
||
<p>Being conscious of the cache line concept is critical to understanding how to organize data in data-intensive applications. A CPU doesn’t fetch memory word by word; instead, it usually copies a memory block to a 64-byte cache line. To get the most out of each individual cache line, enforce spatial locality.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/91-cpu-caches/cache-line/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Slice of structs vs. struct of slices</li>
|
||
</ul>
|
||
<!-- TODO -->
|
||
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/91-cpu-caches/slice-structs/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Predictability</li>
|
||
</ul>
|
||
<p>Making code predictable for the CPU can also be an efficient way to optimize certain functions. For example, a unit or constant stride is predictable for the CPU, but a non-unit stride (for example, a linked list) isn’t predictable.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/91-cpu-caches/predictability/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<ul>
|
||
<li>Cache placement policy</li>
|
||
</ul>
|
||
<p>To avoid a critical stride, hence utilizing only a tiny portion of the cache, be aware that caches are partitioned.</p>
|
||
<h3 id="writing-concurrent-code-that-leads-to-false-sharing-92">Writing concurrent code that leads to false sharing (#92)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Knowing that lower levels of CPU caches aren’t shared across all the cores helps avoid performance-degrading patterns such as false sharing while writing concurrency code. Sharing memory is an illusion.</p>
|
||
</details>
|
||
<p>Read the full section <a href="92-false-sharing/">here</a>.</p>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/92-false-sharing/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-taking-into-account-instruction-level-parallelism-93">Not taking into account instruction-level parallelism (#93)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Use <abbr title="Instruction-Level Parallelism">ILP</abbr> to optimize specific parts of your code to allow a CPU to execute as many parallel instructions as possible. Identifying data hazards is one of the main steps.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/93-instruction-level-parallelism/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-being-aware-of-data-alignment-94">Not being aware of data alignment (#94)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>You can avoid common mistakes by remembering that in Go, basic types are aligned with their own size. For example, keep in mind that reorganizing the fields of a struct by size in descending order can lead to more compact structs (less memory allocation and potentially a better spatial locality).</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/94-data-alignment/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-understanding-stack-vs-heap-95">Not understanding stack vs. heap (#95)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding the fundamental differences between heap and stack should also be part of your core knowledge when optimizing a Go application. Stack allocations are almost free, whereas heap allocations are slower and rely on the <abbr title="Garbage Collector">GC</abbr> to clean the memory.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/95-stack-heap/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-knowing-how-to-reduce-allocations-api-change-compiler-optimizations-and-syncpool-96">Not knowing how to reduce allocations (API change, compiler optimizations, and <code>sync.Pool</code>) (#96)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Reducing allocations is also an essential aspect of optimizing a Go application. This can be done in different ways, such as designing the API carefully to prevent sharing up, understanding the common Go compiler optimizations, and using <code>sync.Pool</code>.</p>
|
||
</details>
|
||
<p><a href="https://github.com/teivah/100-go-mistakes/tree/master/src/12-optimizations/96-reduce-allocations/"><span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span> Source code</a></p>
|
||
<h3 id="not-relying-on-inlining-97">Not relying on inlining (#97)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Use the fast-path inlining technique to efficiently reduce the amortized time to call a function.</p>
|
||
</details>
|
||
<h3 id="not-using-go-diagnostics-tooling-98">Not using Go diagnostics tooling (#98)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Rely on profiling and the execution tracer to understand how an application performs and the parts to optimize.</p>
|
||
</details>
|
||
<p>Read the full section <a href="98-profiling-execution-tracing/">here</a>.</p>
|
||
<h3 id="not-understanding-how-the-gc-works-99">Not understanding how the <abbr title="Garbage Collector">GC</abbr> works (#99)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>Understanding how to tune the <abbr title="Garbage Collector">GC</abbr> can lead to multiple benefits such as handling sudden load increases more efficiently.</p>
|
||
</details>
|
||
<h3 id="not-understanding-the-impacts-of-running-go-in-docker-and-kubernetes-100">Not understanding the impacts of running Go in Docker and Kubernetes (#100)</h3>
|
||
<details class="info" open="open">
|
||
<summary>TL;DR</summary>
|
||
<p>To help avoid CPU throttling when deployed in Docker and Kubernetes, keep in mind that Go isn’t <abbr title="Completely Fair Scheduler">CFS</abbr>-aware.</p>
|
||
</details>
|
||
<p>By default, <abbr title="The variable defines the limit of OS threads in charge of executing user-level code simultaneously">GOMAXPROCS</abbr> is set to the number of OS-apparent logical CPU cores.</p>
|
||
<p>When running some Go code inside Docker and Kubernetes, we must know that Go isn't <abbr title="Completely Fair Scheduler">CFS</abbr>-aware (<a href="https://github.com/golang/go/issues/33803">github.com/golang/go/issues/33803</a>). Therefore, <abbr title="The variable defines the limit of OS threads in charge of executing user-level code simultaneously">GOMAXPROCS</abbr> isn't automatically set to the value of <code>spec.containers.resources.limits.cpu</code> (see <a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/">Kubernetes Resource Management for Pods and Containers</a>); instead, it's set to the number of logical cores on the host machine. The main implication is that it can lead to an increased tail latency in some specific situations.</p>
|
||
<p>One solution is to rely on <a href="https://github.com/uber-go/automaxprocs">uber-go/automaxprocs</a> that automatically set <code>GOMAXPROCS</code> to match the Linux container CPU quota.</p>
|
||
<h2 id="community">Community</h2>
|
||
<p>Thanks to all the contributors:</p>
|
||
<p><a href="https://contrib.rocks/image?repo=teivah/100-go-mistakes">
|
||
<a class="glightbox" href="https://contrib.rocks/image?repo=teivah/100-go-mistakes" data-type="image" data-width="auto" data-height="auto" data-desc-position="bottom"><img src="https://contrib.rocks/image?repo=teivah/100-go-mistakes" alt="Description of the image"></a>
|
||
</a></p>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="__comments">Comments</h2>
|
||
<!-- Insert generated snippet here -->
|
||
<script src="https://giscus.app/client.js"
|
||
data-repo="teivah/100-go-mistakes"
|
||
data-repo-id="MDEwOlJlcG9zaXRvcnkzMjA4MTg5NjI="
|
||
data-category="Discussions"
|
||
data-category-id="DIC_kwDOEx9PEs4CZQUm"
|
||
data-mapping="pathname"
|
||
data-strict="0"
|
||
data-reactions-enabled="1"
|
||
data-emit-metadata="0"
|
||
data-input-position="bottom"
|
||
data-theme="preferred_color_scheme"
|
||
data-lang="en"
|
||
crossorigin="anonymous"
|
||
async>
|
||
</script>
|
||
<!-- Synchronize Giscus theme with palette -->
|
||
<script>
|
||
var giscus = document.querySelector("script[src*=giscus]")
|
||
|
||
// Set palette on initial load
|
||
var palette = __md_get("__palette")
|
||
if (palette && typeof palette.color === "object") {
|
||
var theme = palette.color.scheme === "slate"
|
||
? "transparent_dark"
|
||
: "light"
|
||
|
||
// Instruct Giscus to set theme
|
||
giscus.setAttribute("data-theme", theme)
|
||
}
|
||
|
||
// Register event handlers after documented loaded
|
||
document.addEventListener("DOMContentLoaded", function() {
|
||
var ref = document.querySelector("[data-md-component=palette]")
|
||
ref.addEventListener("change", function() {
|
||
var palette = __md_get("__palette")
|
||
if (palette && typeof palette.color === "object") {
|
||
var theme = palette.color.scheme === "slate"
|
||
? "transparent_dark"
|
||
: "light"
|
||
|
||
// Instruct Giscus to change theme
|
||
var frame = document.querySelector(".giscus-frame")
|
||
frame.contentWindow.postMessage(
|
||
{ giscus: { setConfig: { theme } } },
|
||
"https://giscus.app"
|
||
)
|
||
}
|
||
})
|
||
})
|
||
</script>
|
||
|
||
|
||
</article>
|
||
</div>
|
||
|
||
|
||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||
</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 - 2024 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.5.1 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": ["navigation.tabs", "navigation.tabs.sticky", "search.highlight", "search.share", "search.suggest", "content.code.copy", "navigation.expand", "navigation.sections", "announce.dismiss", "toc.follow", "content.code.annotate", "content.tooltips"], "search": "assets/javascripts/workers/search.b8dbb3d2.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.8fd75fb4.min.js"></script>
|
||
|
||
|
||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WTPX6GZT"
|
||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||
|
||
<script>document$.subscribe(() => {const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});})</script></body>
|
||
</html> |