Como quebrar uma longa linha de código em Golang?

107

Vindo do Python, não estou acostumado a ver linhas de código com mais de 80 colunas. Então, quando eu encontro isso:

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

Eu tentei quebrá-lo para

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

Mas eu consigo

 syntax error: unexpected \

Eu também tentei quebrar a linha pressionando enter e colocar um ponto e vírgula no final:

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

Mas eu novamente consigo:

syntax error: unexpected .

Então, estou me perguntando qual é a maneira golangica de fazer isso?

Karlom
fonte

Respostas:

121

Primeiro, algumas informações básicas. A gramática formal do Go usa ponto- ";"e- vírgula como terminadores em muitas produções, mas os programas Go podem omitir a maioria deles (e eles devem ter uma fonte mais clara e facilmente legível; gofmttambém remove pontos-e-vírgulas desnecessários).

A especificação lista as regras exatas. Especificação: ponto e vírgula:

A gramática formal usa ponto-e-vírgula ";" como terminadores em uma série de produções. Os programas Go podem omitir a maioria desses pontos-e-vírgulas usando as duas regras a seguir:

  1. Quando a entrada é dividida em tokens, um ponto e vírgula é inserido automaticamente no fluxo de token imediatamente após o token final de uma linha se esse token for

  2. Para permitir que instruções complexas ocupem uma única linha, um ponto-e-vírgula pode ser omitido antes de um ")" ou "}" de fechamento.

Como você pode ver, se inserir um caractere de nova linha após o parêntese ), um ponto-e-vírgula ;será inserido automaticamente e a próxima linha não será tratada como a continuação da linha anterior. Isso é o que aconteceu no seu caso e, portanto, a próxima linha, começando com .Scan(&ReadUser.ID,..., apresentará um erro de tempo de compilação, pois isso por si só (sem a linha anterior) é um erro de tempo de compilação:syntax error: unexpected .

Portanto, você pode quebrar sua linha em qualquer ponto que não entre em conflito com as regras listadas no ponto 1.acima.

Normalmente, você pode quebrar suas linhas após a vírgula ,, após a abertura parêntese por exemplo (, [, {e, após um ponto .que pode ser referência a um campo ou método de algum valor. Você também pode quebrar sua linha após operadores binários (aqueles que requerem 2 operandos), por exemplo:

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

Uma coisa que vale a pena notar aqui é que se você tiver uma estrutura, fatia ou literal de mapa listando os valores iniciais, e quiser quebrar a linha após listar o último valor, você deve colocar uma vírgula obrigatória, ,mesmo que este seja o último valor e não mais virão, por exemplo:

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

Isso deve estar em conformidade com as regras de ponto-e-vírgula e também para que você possa reorganizar e adicionar novas linhas sem ter que se preocupar em adicionar / remover a vírgula final; por exemplo, você pode simplesmente trocar as 2 linhas sem ter que remover e adicionar uma nova vírgula:

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

O mesmo se aplica ao listar argumentos para uma chamada de função:

fmt.Println("first",
    "second",
    "third",       // Note it ends with a comma
)
icza
fonte
3
Eu continuo colocando uma vírgula no final dos literais javascript. #hatejs
Paulo Scardine
26
TL; DR: Normalmente você pode quebrar suas linhas após a vírgula ,, depois de abrir parênteses, por exemplo (, [, {e depois de um ponto. Que pode estar referenciando um campo ou método de algum valor.
Peeter Kokk
2
Ter que adicionar uma vírgula extra no final me lembra de alguns bugs antigos do IE js, terrível
Christophe Roussy
4
@ChristopheRoussy É subjetivo, eu adoro que todas as linhas tenham que terminar com uma vírgula, e posso reorganizar e adicionar novas linhas com facilidade, sem ter que me preocupar em adicionar / remover vírgulas.
icza
@icza, eu também gosto que terminem com uma vírgula, mas não tendo que fazer para a última :)
Christophe Roussy
22

A maneira mais simples é simplesmente deixar o operador ( .) na primeira linha.

\ continuações de linha também são desencorajadas em muitos guias de estilo python, você pode envolver toda a expressão entre parênteses se estiver indo e voltando entre go e python, pois essa técnica funciona em ambas as linguagens.

tobyodavies
fonte
Boa dica sobre deixar a operadora no final. Funcionou.
Karlom
1
embrulhar entre parênteses não funciona em go afaik. Continue inserindo o ponto-e-vírgula entre parênteses
Adrian Shum
Acabei de experimentar, e Go realmente insere um ponto e vírgula invisível, mesmo entre parênteses. Portanto, isso só funciona em Python, não em Go.
Roland Illig de
@RolandIllig Isso definitivamente funciona: play.golang.org/p/oFKaxLTphU
tobyodavies
Desculpe pela minha formulação, estava me referindo ao uso de parênteses (mas não escrevi isso). Encapsular a expressão entre parênteses pode funcionar em Python, mas não em Go.
Roland Illig
16

É uma questão de estilo, mas gosto de:

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

Como mencionado, isso é uma questão de preferência de estilo. Eu entendo que os criadores do Go sugeriram um estilo baseado em sua experiência, do qual eu aprendi, mas também mantenho um pouco do meu próprio estilo de minha experiência.

Abaixo está como eu formataria isso:

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