panic n'est pas le try/catch de Go. C'est la ligne où la valeur cesse.panic isn't Go's try/catch. It's the line where the value stops.
Tout le volume a tenu une promesse : l'échec est une valeur qu'on rend, qu'on teste, qu'on enveloppe. panic semble la rompre — il déroule la pile, saute par-dessus le code, ressemble à s'y méprendre à l'exception qu'on disait absente. C'est un piège de lecture. panic et error ne sont pas deux outils pour le même travail ; ils répondent à deux registres incompatibles. Une error est un échec attendu : le fichier manquant, la connexion perdue, l'entrée malformée. Le programme a prévu ce cas, et l'appelant peut décider quoi en faire. Un panic est un échec impossible : un invariant rompu, un état qui ne devait jamais exister, un bug du programme contre lui-même. Là, il n'y a rien à décider — l'appelant ne peut pas « gérer » un programme devenu incohérent. La règle tient en une question : est-ce une situation que le code aurait dû anticiper, ou la preuve qu'il est déjà cassé ? La première se rend. La seconde panique.The whole volume kept one promise: failure is a value you return, test, wrap. panic seems to break it — it unwinds the stack, leaps over code, looks exactly like the exception we said was absent. That's a reading trap. panic and error aren't two tools for the same job; they answer two incompatible registers. An error is an expected failure: the missing file, the lost connection, the malformed input. The program planned for this case, and the caller can decide what to do. A panic is an impossible failure: a broken invariant, a state that should never have existed, a bug of the program against itself. There, there's nothing to decide — the caller can't 'handle' a program gone incoherent. The rule fits in one question: is this a situation the code should have anticipated, or proof that it's already broken? The first is returned. The second panics.
// échec ATTENDU : le fichier peut ne pas exister. C'est une valeur. f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("open %s: %w", path, err) // on REND l'erreur } // l'appelant DÉCIDE : réessayer, valeur par défaut, abandonner.
// échec IMPOSSIBLE : cet index est censé être valide, toujours. // s'il ne l'est pas, c'est un BUG du programme, pas une entrée invalide. i := id % len(s.shards) // invariant : i est forcément dans les bornes shard := s.shards[i] if shard == nil { panic("shard nil : invariant rompu") // rien à RENDRE — on STOPPE } // personne ne peut « gérer » un programme incohérent avec lui-même.
La frontière n'est pas technique, elle est sémantique : qui peut décider de la suite ? Si quelqu'un, en amont, peut raisonnablement réagir, c'est une error. Si la seule réponse sensée est « ce programme a un bug, arrête-toi », c'est un panic.The boundary isn't technical, it's semantic: who can decide what comes next? If someone, upstream, can reasonably react, it's an error. If the only sane answer is "this program has a bug, stop," it's a panic.
« Une entrée invalide se rend ; un programme invalide panique. » Le débutant venu d'un langage à exceptions a le réflexe inverse : paniquer pour tout échec, rattraper partout. Le numéro défend la discipline opposée — panic est rare, réservé à l'irrécupérable : un index hors bornes, un nil qui ne devait jamais l'être, une assertion de programme. Pour tout le reste, il y a la valeur qu'on rend."Invalid input is returned; an invalid program panics." The beginner from an exception language has the opposite reflex: panic on every failure, catch everywhere. The issue argues the opposite discipline — panic is rare, reserved for the unrecoverable: an out-of-bounds index, a nil that should never have been, a program assertion. For everything else, there's the value you return.
Tu n'as souvent même pas besoin d'écrire panic : le runtime le fait à ta place quand un invariant fondamental casse. Accéder à un index hors bornes, déréférencer un pointeur nil, diviser par zéro, écrire dans une map nil — autant de panics levés par le langage lui-même. Ce ne sont pas des erreurs que tu aurais dû renvoyer : ce sont des bugs, signalés bruyamment plutôt que masqués. C'est cohérent avec tout le reste du langage : Go préfère un crash net, localisé, à un comportement indéfini qui pourrirait en silence. Quand tu écris panic toi-même, tu ne fais qu'étendre ce mécanisme à tes propres invariants.You often don't even need to write panic: the runtime does it for you when a fundamental invariant breaks. Indexing out of bounds, dereferencing a nil pointer, dividing by zero, writing to a nil map — all panics raised by the language itself. These aren't errors you should have returned: they're bugs, signaled loudly rather than hidden. It fits the rest of the language: Go prefers a clean, localized crash to undefined behavior rotting in silence. When you write panic yourself, you're just extending that mechanism to your own invariants.