How to break a long line of code in Golang?

GoSyntax

Go Problem Overview


Coming from Python, I'm not used to see code lines longer than 80 columns. So when I encounter this:

err := database.QueryRow("select * from users where user_id=?", id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)

I tried to break it to

err := database.QueryRow("select * from users where user_id=?", id) \
	.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)

But I get

 syntax error: unexpected \

I also tried just breaking the line with hitting enter and put a semicolon at the end:

err := database.QueryRow("select * from users where user_id=?", id) 
.Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email);

But the I again get:

syntax error: unexpected .

So I'm wondering what's the golangic way to do so?

Go Solutions


Solution 1 - Go

First some background. The formal grammar of Go uses semicolons ";" as terminators in many productions, but Go programs may omit most of them (and they should to have a clearer, easily readable source; gofmt also removes unnecessary semicolons).

The specification lists the exact rules. Spec: Semicolons:

> The formal grammar uses semicolons ";" as terminators in a number of productions. Go programs may omit most of these semicolons using the following two rules:

> 1. When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is > - an identifier > - an integer, floating-point, imaginary, rune, or string literal > - one of the keywords break, continue, fallthrough, or return > - one of the operators and delimiters ++, --, ), ], or }

> 2. To allow complex statements to occupy a single line, a semicolon may be omitted before a closing ")" or "}".

So as you can see if you insert a newline character after the parenthesis ), a semicolon ; will be inserted automatically and so the next line will not be treated as the continuation of the previous line. This is what happened in your case, and so the next line starting with .Scan(&ReadUser.ID,... will give you a compile-time error as this standing by itself (without the previous line) is a compile-time error: syntax error: unexpected .

So you may break your line at any point which does not conflict with the rules listed under point 1. above.

Typically you can break your lines after comma ,, after opening parenthesis e.g. (, [, {, and after a dot . which may be referencing a field or method of some value. You can also break your line after binary operators (those that require 2 operands), e.g.:

i := 1 +
        2
fmt.Println(i) // Prints 3

One thing worth noting here is that if you have a struct or slice or map literal listing the initial values, and you want to break line after listing the last value, you have to put a mandatory comma , even though this is the last value and no more will follow, e.g.:

s := []int {
    1, 2, 3,
    4, 5, 6,  // Note it ends with a comma
}

This is to conform with the semicolon rules, and also so that you can rearrange and add new lines without having to take care of adding / removing the final comma; e.g. you can simply swap the 2 lines without having to remove and to add a new comma:

s := []int {
    4, 5, 6,
    1, 2, 3,
}

The same applies when listing arguments to a function call:

fmt.Println("first",
    "second",
    "third",       // Note it ends with a comma
)

Solution 2 - Go

The simplest way is to simply leave the operator (.) on the first line.

\ line continuations are also discouraged in many python style guides, you could wrap the whole expression in parens if you are moving back and forth between go and python as this technique works in both languages.

Solution 3 - Go

As mentioned, this is a matter of style preference. I understand that the creators of Go have suggested a style based on their experience of which I learn from but also keep some of my own style from my experience.

Below is how I would format this:

err := database.
  QueryRow("select * from users where user_id=?", id).
  Scan(
    &ReadUser.ID,
    &ReadUser.Name,
    &ReadUser.First,
    &ReadUser.Last,
    &ReadUser.Email,
  )

Solution 4 - Go

It's a matter of style, but I like:

err := database.QueryRow(
	"select * from users where user_id=?", id,
).Scan(
	&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email,
)

Solution 5 - Go

> what's the golangic way to do so?

An automated solution. Unfortunately, gofmt doesn't cover this case so you could use https://github.com/segmentio/golines

Install it via

go install github.com/segmentio/golines@latest

Then run

golines -w -m 80 .

-w means make the changes in-place (default prints to stdout)

-m is max column length

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKarlomView Question on Stackoverflow
Solution 1 - GoiczaView Answer on Stackoverflow
Solution 2 - GotobyodaviesView Answer on Stackoverflow
Solution 3 - GohaloriumView Answer on Stackoverflow
Solution 4 - GopeterSOView Answer on Stackoverflow
Solution 5 - GoMarkView Answer on Stackoverflow