Quando usar os.Exit () e panic ()?

92

Alguém poderia explicar as principais diferenças entre os.Exit()e panic()e como eles são usados na prática Go?

Timur Fayzrakhmanov
fonte
11
Apenas um comentário que esperançosamente ajudará na leitura de código Go no futuro: em muitos códigos de exemplo, panicé usado para sair em caso de erro, puramente devido ao fato de ser fácil de entender, e elimina a importação de quaisquer outros pacotes. Isso não significa que seja uma prática boa ou idiomática! . É apenas um dispositivo de economia de espaço, por exemplo, código. Reserva IRL panicpara situações muito especiais.
Intermernet
1
Hm .. bom) especialmente a abreviatura "IRL" - é nova para mim :) Você poderia explicar como o pânico elimina a importação de pacotes?
Timur Fayzrakhmanov
4
panicé um embutido. É recomendado (dependendo da circunstância) usar algo como os.Exit, log.Fataletc., que retornará um código de erro para o sistema operacional (sempre recomendado, se possível). Todos eles envolvem a importação de um pacote e, portanto, "bagunçam" o código de exemplo. O código de exemplo deve sempre ser usado apenas para demonstrar uma solução para um problema específico. Pode haver outros problemas com o código, que o tornam mais complexo se demonstrado de forma adequada e, portanto, prejudicam a explicação da resposta dada. YMMV.
Intermernet
1
Ok, entendi!) Muito obrigado) Vejo que há outra abreviatura para o meu vocabulário :)
Timur Fayzrakhmanov
2
NP, feliz em ajudar e aumentar seu léxico acrônimo :-)
Intermernet

Respostas:

84

Em primeiro lugar, sempre que você tiver uma pergunta "como ele é usado na prática", uma boa maneira de começar é pesquisar o código-fonte Go (ou qualquer base de código Go grande o suficiente, na verdade) e a documentação do pacote para respostas.

Agora, os.Exite panicsão bastante diferentes. panicé usado quando o programa, ou parte dele, atingiu um estado irrecuperável.

Quando panicé chamado, incluindo implicitamente para erros de tempo de execução, como indexação de uma fatia fora dos limites ou falha em uma asserção de tipo, ele para imediatamente a execução da função atual e começa a desenrolar a pilha da goroutine, executando quaisquer funções adiadas ao longo do caminho. Se esse desenrolar atingir o topo da pilha da goroutine, o programa será encerrado.

os.Exité usado quando você precisa abortar o programa imediatamente, sem possibilidade de recuperação ou execução de uma instrução de limpeza adiada, e também retornar um código de erro (que outros programas podem usar para relatar o que aconteceu). Isso é útil em testes, quando você já sabe que depois que um teste falhar, o outro também falhará, então você pode simplesmente sair agora. Isso também pode ser usado quando o programa tiver feito tudo o que era necessário e agora precisar apenas sair, ou seja, após imprimir uma mensagem de ajuda.

Na maioria das vezes, você não usará panic(em errorvez disso, deverá retornar um ) e quase nunca precisará os.Exitfora de alguns casos em testes e para o encerramento rápido do programa.

Ainar-G
fonte
9
"Isso é útil em testes, quando você já sabe que depois que um teste falhar, o outro falhará também ..." Isso cheira a um antipadrão de teste de testes dependentes. Em um conjunto de testes bem escrito, cada teste é independente; o resultado de qualquer teste específico nunca deve determinar o resultado de qualquer outro teste.
gotgenes
1
@gotgenes Não necessariamente. Se eu tiver um teste de que uma determinada função retorna uma estrutura não nula e esse teste falhar, então posso esperar que todos os testes que examinam os valores da estrutura também falharão. É o código que depende, não os testes. (Dito isso, eu não usaria exitnesse caso, apenas esperaria uma grande pilha de afirmações com falha.)
David Moles
83

Em primeiro lugar, os.Exit()pode ser usado para sair do programa normalmente sem um erro, e não entre em pânico, então essa é uma distinção fundamental. Outra é que o pânico em algum lugar pode ser detectado e ignorado ou registrado usando recover.

Mas se estivermos falando sobre um código de saída incorreto, digamos:

Use panicquando algo der terrivelmente errado, provavelmente um erro do programador que deveria ter sido detectado antes de ir para a produção. É por isso que ele imprime a pilha.

Use os.Exit(errorCode)ou algo parecido se quiser:

  1. controlar o código de saída do programa para fins de script.

  2. deseja uma saída ordenada em um erro esperado (por exemplo, erro de entrada do usuário).

Basicamente, o pânico é para você, um código de saída ruim é para seu usuário.

Not_a_Golfer
fonte
Muito obrigado!)
Timur Fayzrakhmanov
14
"Basicamente, o pânico é para você, um código de saída ruim é para o seu usuário." <- Dica incrível
psousa
1
Poderíamos dizer que panic () está de alguma forma relacionado à chamada assert () usual no C simples? Bem ... eu sei que sempre removo a declaração de chamada antes de enviar para a produção, eu só os habilito ao testar um novo recurso. O que estou dizendo é que na maioria das vezes eu uso assert () para verificar invariantes que acho que devem ser verdadeiras em meu código. Você vê o mesmo uso para panic ()? :-)
yves Baumes
7

As principais diferenças são:

  1. os.Exit ignora a execução da função adiada.
  2. Com os.Exit, você pode especificar o código de saída.
  3. panicestá encerrando, enquanto os.Exitnão. (Parece que outras respostas não mencionam isso.)

Se você precisa executar a função adiada, você não tem escolha a não ser panic. (Por outro lado, se quiser pular a execução da função adiada, use os.Exit.)

Se uma função não vazia for definida da seguinte maneira:

  1. a função contém muitos ramos
  2. todas as filiais são encerradas com returnoupanic

Então você não pode substituir panicpor, os.Exitcaso contrário, o compilador se recusará a compilar o programa, dizendo "falta retorno no final da função". (Go é muito burro aqui, mesmo log.Panicnão encerra uma função.)

Sob outras condições:

  1. Use panicquando algo realmente conectado acontecer, por exemplo, erro de lógica de programação.
  2. Use os.Exitquando quiser uma saída imediata, com o código de saída especificado.
fraco
fonte