├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md └── style.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2019-10-10 2 | 3 | - Initial release. 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at oss-conduct@uber.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository holds the [Uber Go Style Guide](style.md) 2 | -------------------------------------------------------------------------------- /style.md: -------------------------------------------------------------------------------- 1 | 50 | 51 | # Uber Go Style Guide 52 | 53 | ## Table of Contents 54 | 55 | - [Introduction](#introduction) 56 | - [Guidelines](#guidelines) 57 | - [Pointers to Interfaces](#pointers-to-interfaces) 58 | - [Receivers and Interfaces](#receivers-and-interfaces) 59 | - [Zero-value Mutexes are Valid](#zero-value-mutexes-are-valid) 60 | - [Copy Slices and Maps at Boundaries](#copy-slices-and-maps-at-boundaries) 61 | - [Defer to Clean Up](#defer-to-clean-up) 62 | - [Channel Size is One or None](#channel-size-is-one-or-none) 63 | - [Start Enums at One](#start-enums-at-one) 64 | - [Error Types](#error-types) 65 | - [Error Wrapping](#error-wrapping) 66 | - [Handle Type Assertion Failures](#handle-type-assertion-failures) 67 | - [Don't Panic](#dont-panic) 68 | - [Use go.uber.org/atomic](#use-gouberorgatomic) 69 | - [Performance](#performance) 70 | - [Prefer strconv over fmt](#prefer-strconv-over-fmt) 71 | - [Avoid string-to-byte conversion](#avoid-string-to-byte-conversion) 72 | - [Style](#style) 73 | - [Group Similar Declarations](#group-similar-declarations) 74 | - [Import Group Ordering](#import-group-ordering) 75 | - [Package Names](#package-names) 76 | - [Function Names](#function-names) 77 | - [Import Aliasing](#import-aliasing) 78 | - [Function Grouping and Ordering](#function-grouping-and-ordering) 79 | - [Reduce Nesting](#reduce-nesting) 80 | - [Unnecessary Else](#unnecessary-else) 81 | - [Top-level Variable Declarations](#top-level-variable-declarations) 82 | - [Prefix Unexported Globals with _](#prefix-unexported-globals-with-_) 83 | - [Embedding in Structs](#embedding-in-structs) 84 | - [Use Field Names to initialize Structs](#use-field-names-to-initialize-structs) 85 | - [Local Variable Declarations](#local-variable-declarations) 86 | - [nil is a valid slice](#nil-is-a-valid-slice) 87 | - [Reduce Scope of Variables](#reduce-scope-of-variables) 88 | - [Avoid Naked Parameters](#avoid-naked-parameters) 89 | - [Use Raw String Literals to Avoid Escaping](#use-raw-string-literals-to-avoid-escaping) 90 | - [Initializing Struct References](#initializing-struct-references) 91 | - [Format Strings outside Printf](#format-strings-outside-printf) 92 | - [Naming Printf-style Functions](#naming-printf-style-functions) 93 | - [Patterns](#patterns) 94 | - [Test Tables](#test-tables) 95 | - [Functional Options](#functional-options) 96 | 97 | ## Introduction 98 | 99 | Styles are the conventions that govern our code. The term style is a bit of a 100 | misnomer, since these conventions cover far more than just source file 101 | formatting—gofmt handles that for us. 102 | 103 | The goal of this guide is to manage this complexity by describing in detail the 104 | Dos and Don'ts of writing Go code at Uber. These rules exist to keep the code 105 | base manageable while still allowing engineers to use Go language features 106 | productively. 107 | 108 | This guide was originally created by [Prashant Varanasi] and [Simon Newton] as 109 | a way to bring some colleagues up to speed with using Go. Over the years it has 110 | been amended based on feedback from others. 111 | 112 | [Prashant Varanasi]: https://github.com/prashantv 113 | [Simon Newton]: https://github.com/nomis52 114 | 115 | This documents idiomatic conventions in Go code that we follow at Uber. A lot 116 | of these are general guidelines for Go, while others extend upon external 117 | resources: 118 | 119 | 1. [Effective Go](https://golang.org/doc/effective_go.html) 120 | 2. [The Go common mistakes guide](https://github.com/golang/go/wiki/CodeReviewComments) 121 | 122 | All code should be error-free when run through `golint` and `go vet`. We 123 | recommend setting up your editor to: 124 | 125 | - Run `goimports` on save 126 | - Run `golint` and `go vet` to check for errors 127 | 128 | You can find information in editor support for Go tools here: 129 | 130 | 131 | ## Guidelines 132 | 133 | ### Pointers to Interfaces 134 | 135 | You almost never need a pointer to an interface. You should be passing 136 | interfaces as values—the underlying data can still be a pointer. 137 | 138 | An interface is two fields: 139 | 140 | 1. A pointer to some type-specific information. You can think of this as 141 | "type." 142 | 2. Data pointer. If the data stored is a pointer, it’s stored directly. If 143 | the data stored is a value, then a pointer to the value is stored. 144 | 145 | If you want interface methods to modify the underlying data, you must use a 146 | pointer. 147 | 148 | ### Receivers and Interfaces 149 | 150 | Methods with value receivers can be called on pointers as well as values. 151 | 152 | For example, 153 | 154 | ```go 155 | type S struct { 156 | data string 157 | } 158 | 159 | func (s S) Read() string { 160 | return s.data 161 | } 162 | 163 | func (s *S) Write(str string) { 164 | s.data = str 165 | } 166 | 167 | sVals := map[int]S{1: {"A"}} 168 | 169 | // You can only call Read using a value 170 | sVals[1].Read() 171 | 172 | // This will not compile: 173 | // sVals[0].Write("test") 174 | 175 | sPtrs := map[int]*S{1: {"A"}} 176 | 177 | // You can call both Read and Write using a pointer 178 | sPtrs[1].Read() 179 | sPtrs[1].Write("test") 180 | ``` 181 | 182 | Similarly, an interface can be satisfied by a pointer, even if the method has a 183 | value receiver. 184 | 185 | ```go 186 | type F interface { 187 | f() 188 | } 189 | 190 | type S1 struct{} 191 | 192 | func (s S1) f() {} 193 | 194 | type S2 struct{} 195 | 196 | func (s *S2) f() {} 197 | 198 | s1Val := S1{} 199 | s1Ptr := &S1{} 200 | s2Val := S2{} 201 | s2Ptr := &S2{} 202 | 203 | var i F 204 | i = s1Val 205 | i = s1Ptr 206 | i = s2Ptr 207 | 208 | // The following doesn't compile, since s2Val is a value, and there is no value receiver for f. 209 | // i = s2Val 210 | ``` 211 | 212 | Effective Go has a good write up on [Pointers vs. Values]. 213 | 214 | [Pointers vs. Values]: https://golang.org/doc/effective_go.html#pointers_vs_values 215 | 216 | ### Zero-value Mutexes are Valid 217 | 218 | The zero-value of `sync.Mutex` and `sync.RWMutex` is valid, so you almost 219 | never need a pointer to a mutex. 220 | 221 | 222 | 223 | 224 | 239 |
BadGood
225 | 226 | ```go 227 | mu := new(sync.Mutex) 228 | mu.Lock() 229 | ``` 230 | 231 | 232 | 233 | ```go 234 | var mu sync.Mutex 235 | mu.Lock() 236 | ``` 237 | 238 |
240 | 241 | ```go 242 | var mu sync.Mutex 243 | 244 | mu.Lock() 245 | defer mu.Unlock() 246 | ``` 247 | 248 | If you use a struct by pointer, then the mutex can be a non-pointer field or, 249 | preferably, embedded directly into the struct. 250 | 251 | 252 | 253 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
254 | 255 | ```go 256 | type smap struct { 257 | sync.Mutex 258 | 259 | data map[string]string 260 | } 261 | 262 | func newSMap() *smap { 263 | return &smap{ 264 | data: make(map[string]string), 265 | } 266 | } 267 | 268 | func (m *smap) Get(k string) string { 269 | m.Lock() 270 | defer m.Unlock() 271 | 272 | return m.data[k] 273 | } 274 | ``` 275 | 276 | 277 | 278 | ```go 279 | type SMap struct { 280 | mu sync.Mutex 281 | 282 | data map[string]string 283 | } 284 | 285 | func NewSMap() *SMap { 286 | return &SMap{ 287 | data: make(map[string]string), 288 | } 289 | } 290 | 291 | func (m *SMap) Get(k string) string { 292 | m.mu.Lock() 293 | defer m.mu.Unlock() 294 | 295 | return m.data[k] 296 | } 297 | ``` 298 | 299 |
Embed for private types or types that need to implement the Mutex interface.For exported types, use a private lock.
308 | 309 | ### Copy Slices and Maps at Boundaries 310 | 311 | Slices and maps contain pointers to the underlying data so be wary of scenarios 312 | when they need to be copied. 313 | 314 | #### Receiving Slices and Maps 315 | 316 | Keep in mind that users can modify a map or slice you received as an argument 317 | if you store a reference to it. 318 | 319 | 320 | 321 | 322 | 323 | 338 | 354 | 355 | 356 | 357 |
Bad Good
324 | 325 | ```go 326 | func (d *Driver) SetTrips(trips []Trip) { 327 | d.trips = trips 328 | } 329 | 330 | trips := ... 331 | d1.SetTrips(trips) 332 | 333 | // Did you mean to modify d1.trips? 334 | trips[0] = ... 335 | ``` 336 | 337 | 339 | 340 | ```go 341 | func (d *Driver) SetTrips(trips []Trip) { 342 | d.trips = make([]Trip, len(trips)) 343 | copy(d.trips, trips) 344 | } 345 | 346 | trips := ... 347 | d1.SetTrips(trips) 348 | 349 | // We can now modify trips[0] without affecting d1.trips. 350 | trips[0] = ... 351 | ``` 352 | 353 |
358 | 359 | #### Returning Slices and Maps 360 | 361 | Similarly, be wary of user modifications to maps or slices exposing internal 362 | state. 363 | 364 | 365 | 366 | 367 | 413 |
BadGood
368 | 369 | ```go 370 | type Stats struct { 371 | sync.Mutex 372 | 373 | counters map[string]int 374 | } 375 | 376 | // Snapshot returns the current stats. 377 | func (s *Stats) Snapshot() map[string]int { 378 | s.Lock() 379 | defer s.Unlock() 380 | 381 | return s.counters 382 | } 383 | 384 | // snapshot is no longer protected by the lock! 385 | snapshot := stats.Snapshot() 386 | ``` 387 | 388 | 389 | 390 | ```go 391 | type Stats struct { 392 | sync.Mutex 393 | 394 | counters map[string]int 395 | } 396 | 397 | func (s *Stats) Snapshot() map[string]int { 398 | s.Lock() 399 | defer s.Unlock() 400 | 401 | result := make(map[string]int, len(s.counters)) 402 | for k, v := range s.counters { 403 | result[k] = v 404 | } 405 | return result 406 | } 407 | 408 | // Snapshot is now a copy. 409 | snapshot := stats.Snapshot() 410 | ``` 411 | 412 |
414 | 415 | ### Defer to Clean Up 416 | 417 | Use defer to clean up resources such as files and locks. 418 | 419 | 420 | 421 | 422 | 457 |
BadGood
423 | 424 | ```go 425 | p.Lock() 426 | if p.count < 10 { 427 | p.Unlock() 428 | return p.count 429 | } 430 | 431 | p.count++ 432 | newCount := p.count 433 | p.Unlock() 434 | 435 | return newCount 436 | 437 | // easy to miss unlocks due to multiple returns 438 | ``` 439 | 440 | 441 | 442 | ```go 443 | p.Lock() 444 | defer p.Unlock() 445 | 446 | if p.count < 10 { 447 | return p.count 448 | } 449 | 450 | p.count++ 451 | return p.count 452 | 453 | // more readable 454 | ``` 455 | 456 |
458 | 459 | Defer has an extremely small overhead and should be avoided only if you can 460 | prove that your function execution time is in the order of nanoseconds. The 461 | readability win of using defers is worth the miniscule cost of using them. This 462 | is especially true for larger methods that have more than simple memory 463 | accesses, where the other computations are more significant than the `defer`. 464 | 465 | ### Channel Size is One or None 466 | 467 | Channels should usually have a size of one or be unbuffered. By default, 468 | channels are unbuffered and have a size of zero. Any other size 469 | must be subject to a high level of scrutiny. Consider how the size is 470 | determined, what prevents the channel from filling up under load and blocking 471 | writers, and what happens when this occurs. 472 | 473 | 474 | 475 | 476 | 493 |
BadGood
477 | 478 | ```go 479 | // Ought to be enough for anybody! 480 | c := make(chan int, 64) 481 | ``` 482 | 483 | 484 | 485 | ```go 486 | // Size of one 487 | c := make(chan int, 1) // or 488 | // Unbuffered channel, size of zero 489 | c := make(chan int) 490 | ``` 491 | 492 |
494 | 495 | ### Start Enums at One 496 | 497 | The standard way of introducing enumerations in Go is to declare a custom type 498 | and a `const` group with `iota`. Since variables have a 0 default value, you 499 | should usually start your enums on a non-zero value. 500 | 501 | 502 | 503 | 504 | 533 |
BadGood
505 | 506 | ```go 507 | type Operation int 508 | 509 | const ( 510 | Add Operation = iota 511 | Subtract 512 | Multiply 513 | ) 514 | 515 | // Add=0, Subtract=1, Multiply=2 516 | ``` 517 | 518 | 519 | 520 | ```go 521 | type Operation int 522 | 523 | const ( 524 | Add Operation = iota + 1 525 | Subtract 526 | Multiply 527 | ) 528 | 529 | // Add=1, Subtract=2, Multiply=3 530 | ``` 531 | 532 |
534 | 535 | There are cases where using the zero value makes sense, for example when the 536 | zero value case is the desirable default behavior. 537 | 538 | ```go 539 | type LogOutput int 540 | 541 | const ( 542 | LogToStdout LogOutput = iota 543 | LogToFile 544 | LogToRemote 545 | ) 546 | 547 | // LogToStdout=0, LogToFile=1, LogToRemote=2 548 | ``` 549 | 550 | 551 | 552 | ### Error Types 553 | 554 | There are various options for declaring errors: 555 | 556 | - [`errors.New`] for errors with simple static strings 557 | - [`fmt.Errorf`] for formatted error strings 558 | - Custom types that implement an `Error()` method 559 | - Wrapped errors using [`"pkg/errors".Wrap`] 560 | 561 | When returning errors, consider the following to determine the best choice: 562 | 563 | - Is this a simple error that needs no extra information? If so, [`errors.New`] 564 | should suffice. 565 | - Do the clients need to detect and handle this error? If so, you should use a 566 | custom type, and implement the `Error()` method. 567 | - Are you propagating an error returned by a downstream function? If so, check 568 | the [section on error wrapping](#error-wrapping). 569 | - Otherwise, [`fmt.Errorf`] is okay. 570 | 571 | [`errors.New`]: https://golang.org/pkg/errors/#New 572 | [`fmt.Errorf`]: https://golang.org/pkg/fmt/#Errorf 573 | [`"pkg/errors".Wrap`]: https://godoc.org/github.com/pkg/errors#Wrap 574 | 575 | If the client needs to detect the error, and you have created a simple error 576 | using [`errors.New`], use a var for the error. 577 | 578 | 579 | 580 | 581 | 626 |
BadGood
582 | 583 | ```go 584 | // package foo 585 | 586 | func Open() error { 587 | return errors.New("could not open") 588 | } 589 | 590 | // package bar 591 | 592 | func use() { 593 | if err := foo.Open(); err != nil { 594 | if err.Error() == "could not open" { 595 | // handle 596 | } else { 597 | panic("unknown error") 598 | } 599 | } 600 | } 601 | ``` 602 | 603 | 604 | 605 | ```go 606 | // package foo 607 | 608 | var ErrCouldNotOpen = errors.New("could not open") 609 | 610 | func Open() error { 611 | return ErrCouldNotOpen 612 | } 613 | 614 | // package bar 615 | 616 | if err := foo.Open(); err != nil { 617 | if err == foo.ErrCouldNotOpen { 618 | // handle 619 | } else { 620 | panic("unknown error") 621 | } 622 | } 623 | ``` 624 | 625 |
627 | 628 | If you have an error that clients may need to detect, and you would like to add 629 | more information to it (e.g., it is not a static string), then you should use a 630 | custom type. 631 | 632 | 633 | 634 | 635 | 680 |
BadGood
636 | 637 | ```go 638 | func open(file string) error { 639 | return fmt.Errorf("file %q not found", file) 640 | } 641 | 642 | func use() { 643 | if err := open(); err != nil { 644 | if strings.Contains(err.Error(), "not found") { 645 | // handle 646 | } else { 647 | panic("unknown error") 648 | } 649 | } 650 | } 651 | ``` 652 | 653 | 654 | 655 | ```go 656 | type errNotFound struct { 657 | file string 658 | } 659 | 660 | func (e errNotFound) Error() string { 661 | return fmt.Sprintf("file %q not found", e.file) 662 | } 663 | 664 | func open(file string) error { 665 | return errNotFound{file: file} 666 | } 667 | 668 | func use() { 669 | if err := open(); err != nil { 670 | if _, ok := err.(errNotFound); ok { 671 | // handle 672 | } else { 673 | panic("unknown error") 674 | } 675 | } 676 | } 677 | ``` 678 | 679 |
681 | 682 | Be careful with exporting custom error types directly since they become part of 683 | the public API of the package. It is preferable to expose matcher functions to 684 | check the error instead. 685 | 686 | ```go 687 | // package foo 688 | 689 | type errNotFound struct { 690 | file string 691 | } 692 | 693 | func (e errNotFound) Error() string { 694 | return fmt.Sprintf("file %q not found", e.file) 695 | } 696 | 697 | func IsNotFoundError(err error) bool { 698 | _, ok := err.(errNotFound) 699 | return ok 700 | } 701 | 702 | func Open(file string) error { 703 | return errNotFound{file: file} 704 | } 705 | 706 | // package bar 707 | 708 | if err := foo.Open("foo"); err != nil { 709 | if foo.IsNotFoundError(err) { 710 | // handle 711 | } else { 712 | panic("unknown error") 713 | } 714 | } 715 | ``` 716 | 717 | 718 | 719 | ### Error Wrapping 720 | 721 | There are three main options for propagating errors if a call fails: 722 | 723 | - Return the original error if there is no additional context to add and you 724 | want to maintain the original error type. 725 | - Add context using [`"pkg/errors".Wrap`] so that the error message provides 726 | more context and [`"pkg/errors".Cause`] can be used to extract the original 727 | error. 728 | - Use [`fmt.Errorf`] if the callers do not need to detect or handle that 729 | specific error case. 730 | 731 | It is recommended to add context where possible so that instead of a vague 732 | error such as "connection refused", you get more useful errors such as "failed to 733 | call service foo: connection refused". 734 | 735 | See also [Don't just check errors, handle them gracefully]. 736 | 737 | [`"pkg/errors".Cause`]: https://godoc.org/github.com/pkg/errors#Cause 738 | [Don't just check errors, handle them gracefully]: https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully 739 | 740 | ### Handle Type Assertion Failures 741 | 742 | The single return value form of a [type assertion] will panic on an incorrect 743 | type. Therefore, always use the "comma ok" idiom. 744 | 745 | [type assertion]: https://golang.org/ref/spec#Type_assertions 746 | 747 | 748 | 749 | 750 | 766 |
BadGood
751 | 752 | ```go 753 | t := i.(string) 754 | ``` 755 | 756 | 757 | 758 | ```go 759 | t, ok := i.(string) 760 | if !ok { 761 | // handle the error gracefully 762 | } 763 | ``` 764 | 765 |
767 | 768 | 770 | 771 | ### Don't Panic 772 | 773 | Code running in production must avoid panics. Panics are a major source of 774 | [cascading failures]. If an error occurs, the function must return an error and 775 | allow the caller to decide how to handle it. 776 | 777 | [cascading failures]: https://en.wikipedia.org/wiki/Cascading_failure 778 | 779 | 780 | 781 | 782 | 824 |
BadGood
783 | 784 | ```go 785 | func foo(bar string) { 786 | if len(bar) == 0 { 787 | panic("bar must not be empty") 788 | } 789 | // ... 790 | } 791 | 792 | func main() { 793 | if len(os.Args) != 2 { 794 | fmt.Println("USAGE: foo ") 795 | os.Exit(1) 796 | } 797 | foo(os.Args[1]) 798 | } 799 | ``` 800 | 801 | 802 | 803 | ```go 804 | func foo(bar string) error { 805 | if len(bar) == 0 806 | return errors.New("bar must not be empty") 807 | } 808 | // ... 809 | return nil 810 | } 811 | 812 | func main() { 813 | if len(os.Args) != 2 { 814 | fmt.Println("USAGE: foo ") 815 | os.Exit(1) 816 | } 817 | if err := foo(os.Args[1]); err != nil { 818 | panic(err) 819 | } 820 | } 821 | ``` 822 | 823 |
825 | 826 | Panic/recover is not an error handling strategy. A program must panic only when 827 | something irrecoverable happens such as a nil dereference. An exception to this is 828 | program initialization: bad things at program startup that should abort the 829 | program may cause panic. 830 | 831 | ```go 832 | var _statusTemplate = template.Must(template.New("name").Parse("_statusHTML")) 833 | ``` 834 | 835 | Even in tests, prefer `t.Fatal` or `t.FailNow` over panics to ensure that the 836 | test is marked as failed. 837 | 838 | 839 | 840 | 841 | 864 |
BadGood
842 | 843 | ```go 844 | // func TestFoo(t *testing.T) 845 | 846 | f, err := ioutil.TempFile("", "test") 847 | if err != nil { 848 | panic("failed to set up test") 849 | } 850 | ``` 851 | 852 | 853 | 854 | ```go 855 | // func TestFoo(t *testing.T) 856 | 857 | f, err := ioutil.TempFile("", "test") 858 | if err != nil { 859 | t.Fatal("failed to set up test") 860 | } 861 | ``` 862 | 863 |
865 | 866 | 867 | 868 | ### Use go.uber.org/atomic 869 | 870 | Atomic operations with the [sync/atomic] package operate on the raw types 871 | (`int32`, `int64`, etc.) so it is easy to forget to use the atomic operation to 872 | read or modify the variables. 873 | 874 | [go.uber.org/atomic] adds type safety to these operations by hiding the 875 | underlying type. Additionally, it includes a convenient `atomic.Bool` type. 876 | 877 | [go.uber.org/atomic]: https://godoc.org/go.uber.org/atomic 878 | [sync/atomic]: https://golang.org/pkg/sync/atomic/ 879 | 880 | 881 | 882 | 883 | 924 |
BadGood
884 | 885 | ```go 886 | type foo struct { 887 | running int32 // atomic 888 | } 889 | 890 | func (f* foo) start() { 891 | if atomic.SwapInt32(&f.running, 1) == 1 { 892 | // already running… 893 | return 894 | } 895 | // start the Foo 896 | } 897 | 898 | func (f *foo) isRunning() bool { 899 | return f.running == 1 // race! 900 | } 901 | ``` 902 | 903 | 904 | 905 | ```go 906 | type foo struct { 907 | running atomic.Bool 908 | } 909 | 910 | func (f *foo) start() { 911 | if f.running.Swap(true) { 912 | // already running… 913 | return 914 | } 915 | // start the Foo 916 | } 917 | 918 | func (f *foo) isRunning() bool { 919 | return f.running.Load() 920 | } 921 | ``` 922 | 923 |
925 | 926 | ## Performance 927 | 928 | Performance-specific guidelines apply only to the hot path. 929 | 930 | ### Prefer strconv over fmt 931 | 932 | When converting primitives to/from strings, `strconv` is faster than 933 | `fmt`. 934 | 935 | 936 | 937 | 938 | 953 |
BadGood
939 | 940 | ```go 941 | var i int = ... 942 | s := fmt.Sprint(i) 943 | ``` 944 | 945 | 946 | 947 | ```go 948 | var i int = ... 949 | s := strconv.Itoa(i) 950 | ``` 951 | 952 |
954 | 955 | ### Avoid string-to-byte conversion 956 | 957 | Do not create byte slices from a fixed string repeatedly. Instead, perform the 958 | conversion once and capture the result. 959 | 960 | 961 | 962 | 963 | 981 | 994 |
BadGood
964 | 965 | ```go 966 | for i := 0; i < b.N; i++ { 967 | w.Write([]byte("Hello world")) 968 | } 969 | ``` 970 | 971 | 972 | 973 | ```go 974 | data := []byte("Hello world") 975 | for i := 0; i < b.N; i++ { 976 | w.Write(data) 977 | } 978 | ``` 979 | 980 |
982 | 983 | ``` 984 | BenchmarkBad-4 50000000 22.2 ns/op 985 | ``` 986 | 987 | 988 | 989 | ``` 990 | BenchmarkGood-4 500000000 3.25 ns/op 991 | ``` 992 | 993 |
995 | 996 | ## Style 997 | 998 | ### Group Similar Declarations 999 | 1000 | Go supports grouping similar declarations. 1001 | 1002 | 1003 | 1004 | 1005 | 1022 |
BadGood
1006 | 1007 | ```go 1008 | import "a" 1009 | import "b" 1010 | ``` 1011 | 1012 | 1013 | 1014 | ```go 1015 | import ( 1016 | "a" 1017 | "b" 1018 | ) 1019 | ``` 1020 | 1021 |
1023 | 1024 | This also applies to constants, variables, and type declarations. 1025 | 1026 | 1027 | 1028 | 1029 | 1067 |
BadGood
1030 | 1031 | ```go 1032 | 1033 | const a = 1 1034 | const b = 2 1035 | 1036 | 1037 | 1038 | var a = 1 1039 | var b = 2 1040 | 1041 | 1042 | 1043 | type Area float64 1044 | type Volume float64 1045 | ``` 1046 | 1047 | 1048 | 1049 | ```go 1050 | const ( 1051 | a = 1 1052 | b = 2 1053 | ) 1054 | 1055 | var ( 1056 | a = 1 1057 | b = 2 1058 | ) 1059 | 1060 | type ( 1061 | Area float64 1062 | Volume float64 1063 | ) 1064 | ``` 1065 | 1066 |
1068 | 1069 | Only group related declarations. Do not group declarations that are unrelated. 1070 | 1071 | 1072 | 1073 | 1074 | 1102 |
BadGood
1075 | 1076 | ```go 1077 | type Operation int 1078 | 1079 | const ( 1080 | Add Operation = iota + 1 1081 | Subtract 1082 | Multiply 1083 | ENV_VAR = "MY_ENV" 1084 | ) 1085 | ``` 1086 | 1087 | 1088 | 1089 | ```go 1090 | type Operation int 1091 | 1092 | const ( 1093 | Add Operation = iota + 1 1094 | Subtract 1095 | Multiply 1096 | ) 1097 | 1098 | const ENV_VAR = "MY_ENV" 1099 | ``` 1100 | 1101 |
1103 | 1104 | Groups are not limited in where they can be used. For example, you can use them 1105 | inside of functions. 1106 | 1107 | 1108 | 1109 | 1110 | 1137 |
BadGood
1111 | 1112 | ```go 1113 | func f() string { 1114 | var red = color.New(0xff0000) 1115 | var green = color.New(0x00ff00) 1116 | var blue = color.New(0x0000ff) 1117 | 1118 | ... 1119 | } 1120 | ``` 1121 | 1122 | 1123 | 1124 | ```go 1125 | func f() string { 1126 | var ( 1127 | red = color.New(0xff0000) 1128 | green = color.New(0x00ff00) 1129 | blue = color.New(0x0000ff) 1130 | ) 1131 | 1132 | ... 1133 | } 1134 | ``` 1135 | 1136 |
1138 | 1139 | ### Import Group Ordering 1140 | 1141 | There should be two import groups: 1142 | 1143 | - Standard library 1144 | - Everything else 1145 | 1146 | This is the grouping applied by goimports by default. 1147 | 1148 | 1149 | 1150 | 1151 | 1175 |
BadGood
1152 | 1153 | ```go 1154 | import ( 1155 | "fmt" 1156 | "os" 1157 | "go.uber.org/atomic" 1158 | "golang.org/x/sync/errgroup" 1159 | ) 1160 | ``` 1161 | 1162 | 1163 | 1164 | ```go 1165 | import ( 1166 | "fmt" 1167 | "os" 1168 | 1169 | "go.uber.org/atomic" 1170 | "golang.org/x/sync/errgroup" 1171 | ) 1172 | ``` 1173 | 1174 |
1176 | 1177 | ### Package Names 1178 | 1179 | When naming packages, choose a name that is, 1180 | 1181 | - All lower-case. No capitals or underscores. 1182 | - Does not need to be renamed using named imports at most call sites. 1183 | - Short and succint. Remember that the name is identified in full at every call 1184 | site. 1185 | - Not plural. For example, `net/url`, not `net/urls`. 1186 | - Not "common", "util", "shared", or "lib". These are bad, uninformative names. 1187 | 1188 | See also [Package Names] and [Style guideline for Go packages]. 1189 | 1190 | [Package Names]: https://blog.golang.org/package-names 1191 | [Style guideline for Go packages]: https://rakyll.org/style-packages/ 1192 | 1193 | ### Function Names 1194 | 1195 | We follow the Go community's convention of using [MixedCaps for function 1196 | names]. An exception is made for test functions, which may contain underscores 1197 | for the purpose of grouping related test cases, e.g., 1198 | `TestMyFunction_WhatIsBeingTested`. 1199 | 1200 | [MixedCaps for function names]: https://golang.org/doc/effective_go.html#mixed-caps 1201 | 1202 | ### Import Aliasing 1203 | 1204 | Import aliasing must be used if the package name does not match the last 1205 | element of the import path. 1206 | 1207 | ```go 1208 | import ( 1209 | "net/http" 1210 | 1211 | client "example.com/client-go" 1212 | trace "example.com/trace/v2" 1213 | ) 1214 | ``` 1215 | 1216 | In all other scenarios, import aliases should be avoided unless there is a 1217 | direct conflict between imports. 1218 | 1219 | 1220 | 1221 | 1222 | 1247 |
BadGood
1223 | 1224 | ```go 1225 | import ( 1226 | "fmt" 1227 | "os" 1228 | 1229 | 1230 | nettrace "golang.net/x/trace" 1231 | ) 1232 | ``` 1233 | 1234 | 1235 | 1236 | ```go 1237 | import ( 1238 | "fmt" 1239 | "os" 1240 | "runtime/trace" 1241 | 1242 | nettrace "golang.net/x/trace" 1243 | ) 1244 | ``` 1245 | 1246 |
1248 | 1249 | ### Function Grouping and Ordering 1250 | 1251 | - Functions should be sorted in rough call order. 1252 | - Functions in a file should be grouped by receiver. 1253 | 1254 | Therefore, exported functions should appear first in a file, after 1255 | `struct`, `const`, `var` definitions. 1256 | 1257 | A `newXYZ()`/`NewXYZ()` may appear after the type is defined, but before the 1258 | rest of the methods on the receiver. 1259 | 1260 | Since functions are grouped by receiver, plain utility functions should appear 1261 | towards the end of the file. 1262 | 1263 | 1264 | 1265 | 1266 | 1303 |
BadGood
1267 | 1268 | ```go 1269 | func (s *something) Cost() { 1270 | return calcCost(s.weights) 1271 | } 1272 | 1273 | type something struct{ ... } 1274 | 1275 | func calcCost(n int[]) int {...} 1276 | 1277 | func (s *something) Stop() {...} 1278 | 1279 | func newSomething() *something { 1280 | return &something{} 1281 | } 1282 | ``` 1283 | 1284 | 1285 | 1286 | ```go 1287 | type something struct{ ... } 1288 | 1289 | func newSomething() *something { 1290 | return &something{} 1291 | } 1292 | 1293 | func (s *something) Cost() { 1294 | return calcCost(s.weights) 1295 | } 1296 | 1297 | func (s *something) Stop() {...} 1298 | 1299 | func calcCost(n int[]) int {...} 1300 | ``` 1301 | 1302 |
1304 | 1305 | ### Reduce Nesting 1306 | 1307 | Code should reduce nesting where possible by handling error cases/special 1308 | conditions first and returning early or continuing the loop. Reduce the amount 1309 | of code that is nested multiple levels. 1310 | 1311 | 1312 | 1313 | 1314 | 1349 |
BadGood
1315 | 1316 | ```go 1317 | for _, v := range data { 1318 | if v.F1 == 1 { 1319 | v = process(v) 1320 | if err := v.Call(); err == nil { 1321 | v.Send() 1322 | } else { 1323 | return err 1324 | } 1325 | } else { 1326 | log.Printf("Invalid v: %v", v) 1327 | } 1328 | } 1329 | ``` 1330 | 1331 | 1332 | 1333 | ```go 1334 | for _, v := range data { 1335 | if v.F1 != 1 { 1336 | log.Printf("Invalid v: %v", v) 1337 | continue 1338 | } 1339 | 1340 | v = process(v) 1341 | if err := v.Call(); err != nil { 1342 | return err 1343 | } 1344 | v.Send() 1345 | } 1346 | ``` 1347 | 1348 |
1350 | 1351 | ### Unnecessary Else 1352 | 1353 | If a variable is set in both branches of an if, it can be replaced with a 1354 | single if. 1355 | 1356 | 1357 | 1358 | 1359 | 1380 |
BadGood
1360 | 1361 | ```go 1362 | var a int 1363 | if b { 1364 | a = 100 1365 | } else { 1366 | a = 10 1367 | } 1368 | ``` 1369 | 1370 | 1371 | 1372 | ```go 1373 | a := 10 1374 | if b { 1375 | a = 100 1376 | } 1377 | ``` 1378 | 1379 |
1381 | 1382 | ### Top-level Variable Declarations 1383 | 1384 | At the top level, use the standard `var` keyword. Do not specify the type, 1385 | unless it is not the same type as the expression. 1386 | 1387 | 1388 | 1389 | 1390 | 1409 |
BadGood
1391 | 1392 | ```go 1393 | var _s string = F() 1394 | 1395 | func F() string { return "A" } 1396 | ``` 1397 | 1398 | 1399 | 1400 | ```go 1401 | var _s = F() 1402 | // Since F already states that it returns a string, we don't need to specify 1403 | // the type again. 1404 | 1405 | func F() string { return "A" } 1406 | ``` 1407 | 1408 |
1410 | 1411 | Specify the type if the type of the expression does not match the desired type 1412 | exactly. 1413 | 1414 | ```go 1415 | type myError struct{} 1416 | 1417 | func (myError) Error() string { return "error" } 1418 | 1419 | func F() myError { return myError{} } 1420 | 1421 | var _e error = F() 1422 | // F returns an object of type myError but we want error. 1423 | ``` 1424 | 1425 | ### Prefix Unexported Globals with _ 1426 | 1427 | Prefix unexported top-level `var`s and `const`s with `_` to make it clear when 1428 | they are used that they are global symbols. 1429 | 1430 | Exception: Unexported error values, which should be prefixed with `err`. 1431 | 1432 | Rationale: Top-level variables and constants have a package scope. Using a 1433 | generic name makes it easy to accidentally use the wrong value in a different 1434 | file. 1435 | 1436 | 1437 | 1438 | 1439 | 1473 |
BadGood
1440 | 1441 | ```go 1442 | // foo.go 1443 | 1444 | const ( 1445 | defaultPort = 8080 1446 | defaultUser = "user" 1447 | ) 1448 | 1449 | // bar.go 1450 | 1451 | func Bar() { 1452 | defaultPort := 9090 1453 | ... 1454 | fmt.Println("Default port", defaultPort) 1455 | 1456 | // We will not see a compile error if the first line of 1457 | // Bar() is deleted. 1458 | } 1459 | ``` 1460 | 1461 | 1462 | 1463 | ```go 1464 | // foo.go 1465 | 1466 | const ( 1467 | _defaultPort = 8080 1468 | _defaultUser = "user" 1469 | ) 1470 | ``` 1471 | 1472 |
1474 | 1475 | ### Embedding in Structs 1476 | 1477 | Embedded types (such as mutexes) should be at the top of the field list of a 1478 | struct, and there must be an empty line separating embedded fields from regular 1479 | fields. 1480 | 1481 | 1482 | 1483 | 1484 | 1504 |
BadGood
1485 | 1486 | ```go 1487 | type Client struct { 1488 | version int 1489 | http.Client 1490 | } 1491 | ``` 1492 | 1493 | 1494 | 1495 | ```go 1496 | type Client struct { 1497 | http.Client 1498 | 1499 | version int 1500 | } 1501 | ``` 1502 | 1503 |
1505 | 1506 | ### Use Field Names to initialize Structs 1507 | 1508 | You should almost always specify field names when initializing structs. This is 1509 | now enforced by [`go vet`]. 1510 | 1511 | [`go vet`]: https://golang.org/cmd/vet/ 1512 | 1513 | 1514 | 1515 | 1516 | 1533 |
BadGood
1517 | 1518 | ```go 1519 | k := User{"John", "Doe", true} 1520 | ``` 1521 | 1522 | 1523 | 1524 | ```go 1525 | k := User{ 1526 | FirstName: "John", 1527 | LastName: "Doe", 1528 | Admin: true, 1529 | } 1530 | ``` 1531 | 1532 |
1534 | 1535 | Exception: Field names *may* be omitted in test tables when there are 3 or 1536 | fewer fields. 1537 | 1538 | ```go 1539 | tests := []struct{ 1540 | }{ 1541 | op Operation 1542 | want string 1543 | }{ 1544 | {Add, "add"}, 1545 | {Subtract, "subtract"}, 1546 | } 1547 | ``` 1548 | 1549 | ### Local Variable Declarations 1550 | 1551 | Short variable declarations (`:=`) should be used if a variable is being set to 1552 | some value explicitly. 1553 | 1554 | 1555 | 1556 | 1557 | 1570 |
BadGood
1558 | 1559 | ```go 1560 | var s = "foo" 1561 | ``` 1562 | 1563 | 1564 | 1565 | ```go 1566 | s := "foo" 1567 | ``` 1568 | 1569 |
1571 | 1572 | However, there are cases where the default value is clearer when the `var` 1573 | keyword is use. [Declaring Empty Slices], for example. 1574 | 1575 | [Declaring Empty Slices]: https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices 1576 | 1577 | 1578 | 1579 | 1580 | 1607 |
BadGood
1581 | 1582 | ```go 1583 | func f(list []int) { 1584 | filtered := []int{} 1585 | for _, v := range list { 1586 | if v > 10 { 1587 | filtered = append(filtered, v) 1588 | } 1589 | } 1590 | } 1591 | ``` 1592 | 1593 | 1594 | 1595 | ```go 1596 | func f(list []int) { 1597 | var filtered []int 1598 | for _, v := range list { 1599 | if v > 10 { 1600 | filtered = append(filtered, v) 1601 | } 1602 | } 1603 | } 1604 | ``` 1605 | 1606 |
1608 | 1609 | ### nil is a valid slice 1610 | 1611 | `nil` is a valid slice of length 0. This means that, 1612 | 1613 | - You should not return a slice of length zero explicitly. Return `nil` 1614 | instead. 1615 | 1616 | 1617 | 1618 | 1619 | 1636 |
BadGood
1620 | 1621 | ```go 1622 | if x == "" { 1623 | return []int{} 1624 | } 1625 | ``` 1626 | 1627 | 1628 | 1629 | ```go 1630 | if x == "" { 1631 | return nil 1632 | } 1633 | ``` 1634 | 1635 |
1637 | 1638 | - To check if a slice is empty, always use `len(s) == 0`. Do not check for 1639 | `nil`. 1640 | 1641 | 1642 | 1643 | 1644 | 1661 |
BadGood
1645 | 1646 | ```go 1647 | func isEmpty(s []string) bool { 1648 | return s == nil 1649 | } 1650 | ``` 1651 | 1652 | 1653 | 1654 | ```go 1655 | func isEmpty(s []string) bool { 1656 | return len(s) == 0 1657 | } 1658 | ``` 1659 | 1660 |
1662 | 1663 | - The zero value (a slice declared with `var`) is usable immediately without 1664 | `make()`. 1665 | 1666 | 1667 | 1668 | 1669 | 1699 |
BadGood
1670 | 1671 | ```go 1672 | nums := []int{} 1673 | // or, nums := make([]int) 1674 | 1675 | if add1 { 1676 | nums = append(nums, 1) 1677 | } 1678 | 1679 | if add2 { 1680 | nums = append(nums, 2) 1681 | } 1682 | ``` 1683 | 1684 | 1685 | 1686 | ```go 1687 | var nums []int 1688 | 1689 | if add1 { 1690 | nums = append(nums, 1) 1691 | } 1692 | 1693 | if add2 { 1694 | nums = append(nums, 2) 1695 | } 1696 | ``` 1697 | 1698 |
1700 | 1701 | ### Reduce Scope of Variables 1702 | 1703 | Where possible, reduce scope of variables. Do not reduce the scope if it 1704 | conflicts with [Reduce Nesting](#reduce-nesting). 1705 | 1706 | 1707 | 1708 | 1709 | 1727 |
BadGood
1710 | 1711 | ```go 1712 | err := f.Close() 1713 | if err != nil { 1714 | return err 1715 | } 1716 | ``` 1717 | 1718 | 1719 | 1720 | ```go 1721 | if err := f.Close(); err != nil { 1722 | return err 1723 | } 1724 | ``` 1725 | 1726 |
1728 | 1729 | If you need a result of a function call outside of the if, then you should not 1730 | try to reduce the scope. 1731 | 1732 | 1733 | 1734 | 1735 | 1765 |
BadGood
1736 | 1737 | ```go 1738 | if f, err := os.Open("f"); err == nil { 1739 | _, err = io.WriteString(f, "data") 1740 | if err != nil { 1741 | return err 1742 | } 1743 | return f.Close() 1744 | } else { 1745 | return err 1746 | } 1747 | ``` 1748 | 1749 | 1750 | 1751 | ```go 1752 | f, err := os.Open("f") 1753 | if err != nil { 1754 | return err 1755 | } 1756 | 1757 | if _, err := io.WriteString(f, "data"); err != nil { 1758 | return err 1759 | } 1760 | 1761 | return f.Close() 1762 | ``` 1763 | 1764 |
1766 | 1767 | ### Avoid Naked Parameters 1768 | 1769 | Naked parameters in function calls can hurt readability. Add C-style comments 1770 | (`/* ... */`) for parameter names when their meaning is not obvious. 1771 | 1772 | 1773 | 1774 | 1775 | 1792 |
BadGood
1776 | 1777 | ```go 1778 | // func printInfo(name string, isLocal, done bool) 1779 | 1780 | printInfo("foo", true, true) 1781 | ``` 1782 | 1783 | 1784 | 1785 | ```go 1786 | // func printInfo(name string, isLocal, done bool) 1787 | 1788 | printInfo("foo", true /* isLocal */, true /* done */) 1789 | ``` 1790 | 1791 |
1793 | 1794 | Better yet, replace naked `bool` types with custom types for more readable and 1795 | type-safe code. This allows more than just two states (true/false) for that 1796 | parameter in the future. 1797 | 1798 | ```go 1799 | type Region int 1800 | 1801 | const ( 1802 | UnknownRegion Region = iota 1803 | Local 1804 | ) 1805 | 1806 | type Status int 1807 | 1808 | const ( 1809 | StatusReady = iota + 1 1810 | StatusDone 1811 | // Maybe we will have a StatusInProgress in the future. 1812 | ) 1813 | 1814 | func printInfo(name string, region Region, status Status) 1815 | ``` 1816 | 1817 | ### Use Raw String Literals to Avoid Escaping 1818 | 1819 | Go supports [raw string literals](https://golang.org/ref/spec#raw_string_lit), 1820 | which can span multiple lines and include quotes. Use these to avoid 1821 | hand-escaped strings which are much harder to read. 1822 | 1823 | 1824 | 1825 | 1826 | 1839 |
BadGood
1827 | 1828 | ```go 1829 | wantError := "unknown name:\"test\"" 1830 | ``` 1831 | 1832 | 1833 | 1834 | ```go 1835 | wantError := `unknown error:"test"` 1836 | ``` 1837 | 1838 |
1840 | 1841 | ### Initializing Struct References 1842 | 1843 | Use `&T{}` instead of `new(T)` when initializing struct references so that it 1844 | is consistent with the struct initialization. 1845 | 1846 | 1847 | 1848 | 1849 | 1868 |
BadGood
1850 | 1851 | ```go 1852 | sval := T{Name: "foo"} 1853 | 1854 | // inconsistent 1855 | sptr := new(T) 1856 | sptr.Name = "bar" 1857 | ``` 1858 | 1859 | 1860 | 1861 | ```go 1862 | sval := T{Name: "foo"} 1863 | 1864 | sptr := &T{Name: "bar"} 1865 | ``` 1866 | 1867 |
1869 | 1870 | ### Format Strings outside Printf 1871 | 1872 | If you declare format strings for `Printf`-style functions outside a string 1873 | literal, make them `const` values. 1874 | 1875 | This helps `go vet` perform static analysis of the format string. 1876 | 1877 | 1878 | 1879 | 1880 | 1895 |
BadGood
1881 | 1882 | ```go 1883 | msg := "unexpected values %v, %v\n" 1884 | fmt.Printf(msg, 1, 2) 1885 | ``` 1886 | 1887 | 1888 | 1889 | ```go 1890 | const msg = "unexpected values %v, %v\n" 1891 | fmt.Printf(msg, 1, 2) 1892 | ``` 1893 | 1894 |
1896 | 1897 | ### Naming Printf-style Functions 1898 | 1899 | When you declare a `Printf`-style function, make sure that `go vet` can detect 1900 | it and check the format string. 1901 | 1902 | This means that you should use pre-defined `Printf`-style function 1903 | names if possible. `go vet` will check these by default. See [Printf family] 1904 | for more information. 1905 | 1906 | [Printf family]: https://golang.org/cmd/vet/#hdr-Printf_family 1907 | 1908 | If using the pre-defined names is not an option, end the name you choose with 1909 | f: `Wrapf`, not `Wrap`. `go vet` can be asked to check specific `Printf`-style 1910 | names but they must end with f. 1911 | 1912 | ```shell 1913 | $ go vet -printfuncs=wrapf,statusf 1914 | ``` 1915 | 1916 | See also [go vet: Printf family check]. 1917 | 1918 | [go vet: Printf family check]: https://kuzminva.wordpress.com/2017/11/07/go-vet-printf-family-check/ 1919 | 1920 | ## Patterns 1921 | 1922 | ### Test Tables 1923 | 1924 | Use table-driven tests with [subtests] to avoid duplicating code when the core 1925 | test logic is repetitive. 1926 | 1927 | [subtests]: https://blog.golang.org/subtests 1928 | 1929 | 1930 | 1931 | 1932 | 2001 |
BadGood
1933 | 1934 | ```go 1935 | // func TestSplitHostPort(t *testing.T) 1936 | 1937 | host, port, err := net.SplitHostPort("192.0.2.0:8000") 1938 | require.NoError(t, err) 1939 | assert.Equal(t, "192.0.2.0", host) 1940 | assert.Equal(t, "8000", port) 1941 | 1942 | host, port, err = net.SplitHostPort("192.0.2.0:http") 1943 | require.NoError(t, err) 1944 | assert.Equal(t, "192.0.2.0", host) 1945 | assert.Equal(t, "http", port) 1946 | 1947 | host, port, err = net.SplitHostPort(":8000") 1948 | require.NoError(t, err) 1949 | assert.Equal(t, "", host) 1950 | assert.Equal(t, "8000", port) 1951 | 1952 | host, port, err = net.SplitHostPort("1:8") 1953 | require.NoError(t, err) 1954 | assert.Equal(t, "1", host) 1955 | assert.Equal(t, "8", port) 1956 | ``` 1957 | 1958 | 1959 | 1960 | ```go 1961 | // func TestSplitHostPort(t *testing.T) 1962 | 1963 | tests := []struct{ 1964 | give string 1965 | wantHost string 1966 | wantPort string 1967 | }{ 1968 | { 1969 | give: "192.0.2.0:8000", 1970 | wantHost: "192.0.2.0", 1971 | wantPort: "8000", 1972 | }, 1973 | { 1974 | give: "192.0.2.0:http", 1975 | wantHost: "192.0.2.0", 1976 | wantPort: "http", 1977 | }, 1978 | { 1979 | give: ":8000", 1980 | wantHost: "", 1981 | wantPort: "8000", 1982 | }, 1983 | { 1984 | give: "1:8", 1985 | wantHost: "1", 1986 | wantPort: "8", 1987 | }, 1988 | } 1989 | 1990 | for _, tt := range tests { 1991 | t.Run(tt.give, func(t *testing.T) { 1992 | host, port, err := net.SplitHostPort(tt.give) 1993 | require.NoError(t, err) 1994 | assert.Equal(t, tt.wantHost, host) 1995 | assert.Equal(t, tt.wantPort, port) 1996 | }) 1997 | } 1998 | ``` 1999 | 2000 |
2002 | 2003 | Test tables make it easier to add context to error messages, reduce duplicate 2004 | logic, and add new test cases. 2005 | 2006 | We follow the convention that the slice of structs is referred to as `tests` 2007 | and each test case `tt`. Further, we encourage explicating the input and output 2008 | values for each test case with `give` and `want` prefixes. 2009 | 2010 | ```go 2011 | tests := []struct{ 2012 | give string 2013 | wantHost string 2014 | wantPort string 2015 | }{ 2016 | // ... 2017 | } 2018 | 2019 | for _, tt := range tests { 2020 | // ... 2021 | } 2022 | ``` 2023 | 2024 | ### Functional Options 2025 | 2026 | Functional options is a pattern in which you declare an opaque `Option` type 2027 | that records information in some internal struct. You accept a variadic number 2028 | of these options and act upon the full information recorded by the options on 2029 | the internal struct. 2030 | 2031 | Use this pattern for optional arguments in constructors and other public APIs 2032 | that you foresee needing to expand, especially if you already have three or 2033 | more arguments on those functions. 2034 | 2035 | 2036 | 2037 | 2038 | 2121 |
BadGood
2039 | 2040 | ```go 2041 | // package db 2042 | 2043 | func Connect( 2044 | addr string, 2045 | timeout time.Duration, 2046 | caching bool, 2047 | ) (*Connection, error) { 2048 | // ... 2049 | } 2050 | 2051 | // Timeout and caching must always be provided, 2052 | // even if the user wants to use the default. 2053 | 2054 | db.Connect(addr, db.DefaultTimeout, db.DefaultCaching) 2055 | db.Connect(addr, newTimeout, db.DefaultCaching) 2056 | db.Connect(addr, db.DefaultTimeout, false /* caching */) 2057 | db.Connect(addr, newTimeout, false /* caching */) 2058 | ``` 2059 | 2060 | 2061 | 2062 | ```go 2063 | type options struct { 2064 | timeout time.Duration 2065 | caching bool 2066 | } 2067 | 2068 | // Option overrides behavior of Connect. 2069 | type Option interface { 2070 | apply(*options) 2071 | } 2072 | 2073 | type optionFunc func(*options) 2074 | 2075 | func (f optionFunc) apply(o *options) { 2076 | f(o) 2077 | } 2078 | 2079 | func WithTimeout(t time.Duration) Option { 2080 | return optionFunc(func(o *options) { 2081 | o.timeout = t 2082 | }) 2083 | } 2084 | 2085 | func WithCaching(cache bool) Option { 2086 | return optionFunc(func(o *options) { 2087 | o.caching = cache 2088 | }) 2089 | } 2090 | 2091 | // Connect creates a connection. 2092 | func Connect( 2093 | addr string, 2094 | opts ...Option, 2095 | ) (*Connection, error) { 2096 | options := options{ 2097 | timeout: defaultTimeout, 2098 | caching: defaultCaching, 2099 | } 2100 | 2101 | for _, o := range opts { 2102 | o(&options) 2103 | } 2104 | 2105 | // ... 2106 | } 2107 | 2108 | // Options must be provided only if needed. 2109 | 2110 | db.Connect(addr) 2111 | db.Connect(addr, db.WithTimeout(newTimeout)) 2112 | db.Connect(addr, db.WithCaching(false)) 2113 | db.Connect( 2114 | addr, 2115 | db.WithCaching(false), 2116 | db.WithTimeout(newTimeout), 2117 | ) 2118 | ``` 2119 | 2120 |
2122 | 2123 | See also, 2124 | 2125 | - [Self-referential functions and the design of options] 2126 | - [Functional options for friendly APIs] 2127 | 2128 | [Self-referential functions and the design of options]: https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html 2129 | [Functional options for friendly APIs]: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis 2130 | 2131 | 2133 | --------------------------------------------------------------------------------