Alert

์ด ๊ธ€์€ Claude Code์˜ ๋„์›€์„ ๋ฐ›์•„ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

TL;DR

  • Go์—๋Š” try/except ๊ฐ™์€ ์˜ˆ์™ธ ๊ตฌ๋ฌธ์ด ์—†๊ณ , ํ•จ์ˆ˜๊ฐ€ ์—๋Ÿฌ๋ฅผ ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด ํ˜ธ์ถœ์ž๊ฐ€ if err != nil๋กœ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹
  • error๋Š” Error() string ํ•˜๋‚˜๋งŒ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ , nil์ด ์ธํ„ฐํŽ˜์ด์Šค์˜ zero value๋ผ โ€œ์—๋Ÿฌ ์—†์Œ = nilโ€์ด ์„ฑ๋ฆฝ
  • ์—๋Ÿฌ ์ƒ์„ฑ์€ errors.New์™€ ํฌ๋งคํŒ…์šฉ fmt.Errorf, ๋ฐ˜ํ™˜์€ (๊ฒฐ๊ณผ, error) ๋‹ค์ค‘ ๋ฐ˜ํ™˜ ๊ด€์šฉ๊ตฌ
  • ์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜๋Š” ๋ฏธ๋ฆฌ ์ •์˜ํ•œ ๋Œ€ํ‘œ ์—๋Ÿฌ ๊ฐ’์ด๋ฉฐ, ๋ฌธ์ž์—ด ๋น„๊ต ๋Œ€์‹  errors.Is๋กœ ์ข…๋ฅ˜๋ฅผ ๊ตฌ๋ถ„
  • %w๋กœ ๋ฌธ๋งฅ์„ ๋ง๋ถ™์—ฌ ๋ž˜ํ•‘ํ•˜๋ฉด ์›๋ณธ์ด ๋ณด์กด๋˜๊ณ , errors.Is(๊ฐ’ ๋น„๊ต)ยทerrors.As(ํƒ€์ž… ํ™•์ธ ํ›„ ์ถ”์ถœ)๋กœ ์ฒด์ธ์„ ๊ฒ€์‚ฌ
  • panic/recover๋Š” ํ˜ธ์ถœ์ž๊ฐ€ ์ •์ƒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋Š” ์น˜๋ช…์  ์ƒํ™ฉ ์ „์šฉ์ด๋ฉฐ, ์ผ์ƒ ํ๋ฆ„ ์ œ์–ด์šฉ์ด ์•„๋‹˜

Python์—์„œ ์—๋Ÿฌ๋Š” ์˜ˆ์™ธ(exception)๋‹ค. ํ•จ์ˆ˜ ์–ด๋””์„œ๋“  raise๋กœ ๋˜์ง€๊ณ , ํ˜ธ์ถœ ํ๋ฆ„ ์–ด๋”˜๊ฐ€์˜ try/except๊ฐ€ ๋ฐ›๋Š”๋‹ค. ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ฃฝ๋Š”๋‹ค. ๋˜์ง€๋Š” ์ชฝ๊ณผ ๋ฐ›๋Š” ์ชฝ์ด ์ฝ”๋“œ์ƒ ๋–จ์–ด์ ธ ์žˆ์–ด๋„ ๋™์ž‘ํ•˜๋Š” ๊ฒŒ ์˜ˆ์™ธ์˜ ์žฅ์ ์ด์ž, ํ๋ฆ„์ด ์–ด๋””๋กœ ํŠ€๋Š”์ง€ ์•Œ๊ธฐ ์–ด๋ ค์šด ๋‹จ์ ์ด๋‹ค.

Go๋Š” ์ •๋ฐ˜๋Œ€๋กœ ์„ค๊ณ„๋๋‹ค. ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋Š” ํŠน๋ณ„ํ•œ ๊ตฌ๋ฌธ์ด ์—†๋‹ค. ํ•จ์ˆ˜๋Š” ์—๋Ÿฌ๋ฅผ ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ , ํ˜ธ์ถœ์ž๋Š” ๊ทธ ๊ฐ’์„ ๋งค๋ฒˆ ์†์œผ๋กœ ํ™•์ธํ•œ๋‹ค. โ€œerrors are valuesโ€(์—๋Ÿฌ๋Š” ๊ฐ’์ด๋‹ค)๋ผ๋Š” ํ•œ ์ค„์ด Go ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ฒ ํ•™์˜ ์ „๋ถ€๋‹ค. ๋˜์ง€๊ณ  ๋ฐ›๋Š” ๋งˆ๋ฒ• ๋Œ€์‹ , ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์ฃผ๊ณ ๋ฐ›๋Š” ํ‰๋ฒ”ํ•œ ๋ฐ์ดํ„ฐ๋กœ ๋‹ค๋ฃฌ๋‹ค. ์ด ๊ธ€์€ Python์˜ ์˜ˆ์™ธ์— ์ต์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ Go์˜ ์ด ๋ฐฉ์‹์„ ์ฒ˜์Œ ๋งŒ๋‚ฌ์„ ๋•Œ ํ—ท๊ฐˆ๋ฆฌ๋Š” ์ง€์ ์„ ์ •๋ฆฌํ•œ๋‹ค.


1. error๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋‹ค

Go์—์„œ error๋Š” ํŠน๋ณ„ํ•œ ํ‚ค์›Œ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด์žฅ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค. ์ •์˜๋Š” ์ด๊ฒŒ ์ „๋ถ€๋‹ค.

type error interface {
    Error() string
}

Error() string ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ์–ด๋–ค ํƒ€์ž…์ด๋“  ์—๋Ÿฌ๊ฐ€ ๋œ๋‹ค. 07ํŽธ์—์„œ ๋‹ค๋ฃฌ ๋Œ€๋กœ Go ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋ฉ”์„œ๋“œ ์ง‘ํ•ฉ๋งŒ ๋งŒ์กฑํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ถฉ์กฑ๋˜๋ฏ€๋กœ, ๋ณ„๋„ ์ƒ์†์ด๋‚˜ ๋“ฑ๋ก ์—†์ด๋„ ๋‚ด ํƒ€์ž…์„ ์—๋Ÿฌ๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

type MyError struct {
    Code int
}
 
func (e MyError) Error() string {
    return fmt.Sprintf("error code %d", e.Code)
}

์ด์ œ MyError๋Š” error ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ์กฑํ•œ๋‹ค. ํ•จ์ˆ˜๊ฐ€ error๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž๋ฆฌ์— MyError๋ฅผ ๊ทธ๋Œ€๋กœ ๋Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

nil์ด โ€œ์—๋Ÿฌ ์—†์Œโ€์ธ ์ด์œ 

์—ฌ๊ธฐ์„œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์„ฑ์งˆ ํ•˜๋‚˜๊ฐ€ ํ•ต์‹ฌ์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค. nil์€ ๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์˜ zero value๋‹ค(06ํŽธ์—์„œ ํฌ์ธํ„ฐ์˜ zero value๊ฐ€ nil์ด์—ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋งฅ๋ฝ์ด๋‹ค). error๋„ ์ธํ„ฐํŽ˜์ด์Šค์ด๋ฏ€๋กœ, ์•„์ง ์•„๋ฌด ์—๋Ÿฌ๋„ ๋‹ด๊ธฐ์ง€ ์•Š์€ ์ƒํƒœ๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ nil์ด ๋œ๋‹ค.

๊ทธ๋ž˜์„œ Go๋Š” โ€œ์—๋Ÿฌ๊ฐ€ ์—†๋‹คโ€๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ๋ณ„๋„ ์žฅ์น˜๊ฐ€ ํ•„์š” ์—†๋‹ค. ๊ทธ๋ƒฅ nil์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค. ํ˜ธ์ถœ์ž๋Š” err == nil์ด๋ฉด ์„ฑ๊ณต, err != nil์ด๋ฉด ์‹คํŒจ๋กœ ์ฝ๋Š”๋‹ค. ์ด ๋‹จ์ˆœํ•œ ๊ทœ์น™์ด ๋’ค์— ๋‚˜์˜ฌ ๋ชจ๋“  ํŒจํ„ด์˜ ํ† ๋Œ€๋‹ค.

Python์˜ None๊ณผ ๋‹ค๋ฅธ ์ 

Python์—์„œ None์€ โ€œ๊ฐ’์ด ์—†์Œโ€์„ ๋œปํ•˜๋Š” ๋‹จ์ผ ๊ฐ์ฒด์ผ ๋ฟ, ์—๋Ÿฌ ์ฒ˜๋ฆฌ์™€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๋Š”๋‹ค. ์—๋Ÿฌ๋Š” ์˜ˆ์™ธ๋กœ ๋”ฐ๋กœ ๋˜์ง„๋‹ค. Go์˜ nil์€ โ€œ์—๋Ÿฌ ์—†์Œโ€์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ทœ์•ฝ ์ž์ฒด์— ๋…น์—ฌ ์“ด๋‹ค. ํ•จ์ˆ˜๊ฐ€ error๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ nil์ด๋ฉด, ๊ทธ๊ฑด ๊ณง โ€œ์ด๋ฒˆ์—” ๋ฌธ์ œ์—†๋‹คโ€๋Š” ๋œป์ด๋‹ค.


2. ์—๋Ÿฌ ๋งŒ๋“ค๊ณ  ๋ฐ˜ํ™˜ํ•˜๊ธฐ

์—๋Ÿฌ ๊ฐ’์„ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€๋‹ค.

  • errors.New("๋ฉ”์‹œ์ง€") โ€” ๊ณ ์ • ๋ฌธ์ž์—ด ์—๋Ÿฌ๋ฅผ ๋งŒ๋“ ๋‹ค
  • fmt.Errorf("ํ˜•์‹ %v", ๊ฐ’) โ€” ๊ฐ’์„ ๋ผ์›Œ ๋„ฃ์–ด ํฌ๋งคํŒ…ํ•œ ์—๋Ÿฌ๋ฅผ ๋งŒ๋“ ๋‹ค
import (
    "errors"
    "fmt"
)
 
func sqrt(x float64) (float64, error) {
    if x < 0 {
        return 0, errors.New("์Œ์ˆ˜์˜ ์ œ๊ณฑ๊ทผ์€ ์ •์˜๋˜์ง€ ์•Š์Œ")
    }
    if x > 1e308 {
        return 0, fmt.Errorf("์ž…๋ ฅ๊ฐ’์ด ๋„ˆ๋ฌด ํผ: %v", x)
    }
    return math.Sqrt(x), nil
}

errors.New๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜

errors.New(text)๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ text๋ฅผ ์ž‘์€ ๊ตฌ์กฐ์ฒด์— ๋‹ด๊ณ  ๊ทธ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ ๊ตฌ์กฐ์ฒด๊ฐ€ Error() string ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ ธ error ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ์กฑํ•˜๋ฏ€๋กœ(07ํŽธ), err.Error()๋‚˜ fmt.Println(err)์€ ๊ทธ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ ๋‹ด์•„๋‘” ํ…์ŠคํŠธ๋ฅผ ๊บผ๋‚ธ๋‹ค.

// ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (์š”์•ฝ)
func New(text string) error { return &errorString{text} }
type errorString struct{ s string }
func (e *errorString) Error() string { return e.s }

ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ํ…์ŠคํŠธ๊ฐ€ ๊ฐ™์•„๋„ ํ˜ธ์ถœ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฐ’์ด ๋œ๋‹ค(errors.New("x") == errors.New("x")๋Š” false). ์ด โ€œ๊ฐ’๋งˆ๋‹ค ๊ณ ์œ ํ•จโ€์ด 3๋ฒˆ ์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜์—์„œ errors.Is๊ฐ€ ์ •ํ™•ํžˆ ๊ทธ ๊ฐ’๋งŒ ์žก์•„๋‚ด๋Š” ํ† ๋Œ€๊ฐ€ ๋œ๋‹ค.

(๊ฒฐ๊ณผ, error) ๋‹ค์ค‘ ๋ฐ˜ํ™˜ ๊ด€์šฉ๊ตฌ

05ํŽธ์—์„œ ์˜ˆ๊ณ ํ•œ ํŒจํ„ด์ด ์—ฌ๊ธฐ์„œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋“ฑ์žฅํ•œ๋‹ค. Go ํ•จ์ˆ˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ทธ์ค‘ ๋งˆ์ง€๋ง‰ ๋ฐ˜ํ™˜๊ฐ’์„ error ํƒ€์ž…์œผ๋กœ ๋‘๋Š” ๊ฒƒ์ด ๊ด€์šฉ๊ตฌ๋‹ค.

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Œ")
    }
    return a / b, nil
}

์„ฑ๊ณตํ•˜๋ฉด (๊ฒฐ๊ณผ, nil), ์‹คํŒจํ•˜๋ฉด (zero value, ์—๋Ÿฌ)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์‹คํŒจ ์‹œ ์ฒซ ๋ฐ˜ํ™˜๊ฐ’์„ 0์ด๋‚˜ ๋นˆ ๊ฐ’์œผ๋กœ ์ฑ„์šฐ๋Š” ๊ฑด ๊ด€๋ก€๋‹ค. ์–ด์ฐจํ”ผ ํ˜ธ์ถœ์ž๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋จผ์ € ํ™•์ธํ•˜๊ณ  ๊ฒฐ๊ณผ๋Š” ์•ˆ ์“ธ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์€ ๋ฐ˜ํ™˜๋œ ์—๋Ÿฌ๋ฅผ ๊ณง๋ฐ”๋กœ ํ™•์ธํ•œ๋‹ค.

result, err := divide(10, 0)
if err != nil {
    fmt.Println("์‹คํŒจ:", err)
    return
}
fmt.Println("๊ฒฐ๊ณผ:", result)

if err != nil๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ด ๋ธ”๋ก์ด Go ์ฝ”๋“œ ์ „๋ฐ˜์— ๋์—†์ด ๋ฐ˜๋ณต๋œ๋‹ค. ์ฒ˜์Œ์—” ์žฅํ™ฉํ•ด ๋ณด์ด์ง€๋งŒ, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ง€์ ์ด ์ฝ”๋“œ์— ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ์–ด๋””์„œ ๋ฌด์—‡์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ˆจ์ง€ ์•Š๋Š”๋‹ค.

Python๊ณผ ๋‚˜๋ž€ํžˆ ๋‘๋ฉด

๊ฐ™์€ ์ผ์„ Python์€ ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋˜์ง€๋Š” ์ชฝ์€ raise, ๋ฐ›๋Š” ์ชฝ์€ try/except๋‹ค.

# Python โ€” ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌ
def divide(a, b):
    if b == 0:
        raise ValueError("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Œ")
    return a // b
 
try:
    result = divide(10, 0)
    print("๊ฒฐ๊ณผ:", result)
except ValueError as e:
    print("์‹คํŒจ:", e)

์ฐจ์ด๋ฅผ ์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

PythonGo
์—๋Ÿฌ๋ฅผ ์•Œ๋ฆฌ๋Š” ๋ฒ•raise๋กœ ๋˜์ง๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋Œ๋ ค์คŒ
์—๋Ÿฌ๋ฅผ ๋ฐ›๋Š” ๋ฒ•try/except๋กœ ๊ฐ์Œˆif err != nil๋กœ ํ™•์ธ
์ฒ˜๋ฆฌ ์œ„์น˜ํ˜ธ์ถœ ํ๋ฆ„ ์–ด๋”˜๊ฐ€(๋ฉ€์–ด๋„ ๋จ)ํ˜ธ์ถœ ์งํ›„, ๋ฐ”๋กœ ๊ทธ ์ž๋ฆฌ
์•ˆ ๋ฐ›์œผ๋ฉด์œ„๋กœ ์ „ํŒŒ๋˜๋‹ค ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ๊ทธ๋ƒฅ ๋ฌด์‹œ๋จ(์ปดํŒŒ์ผ์€ ๋จ)

๋งˆ์ง€๋ง‰ ์ค„์ด ์ค‘์š”ํ•˜๋‹ค. Python์€ ์˜ˆ์™ธ๋ฅผ ์•ˆ ๋ฐ›์œผ๋ฉด ๊ฒฐ๊ตญ ํ”„๋กœ๊ทธ๋žจ์ด ์ฃฝ์ง€๋งŒ, Go์—์„œ ์—๋Ÿฌ๋Š” ๊ทธ๋ƒฅ ๊ฐ’์ด๋ผ ๋ฌด์‹œํ•ด๋„ ์ปดํŒŒ์ผ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•˜๋Š” ์ฑ…์ž„์ด ์ „์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์žˆ๋‹ค.

์—๋Ÿฌ๋ฅผ ์˜๋„์ ์œผ๋กœ ๋ฒ„๋ฆด ๋•Œ

์ •๋ง ์—๋Ÿฌ๋ฅผ ๋ฌด์‹œํ•ด๋„ ๋˜๋Š” ์ž๋ฆฌ๋ผ๋ฉด _๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋ฒ„๋ฆฐ๋‹ค. result, _ := divide(10, 2)์ฒ˜๋Ÿผ ์“ฐ๋ฉด โ€œ์—๋Ÿฌ๋ฅผ ๋ดค๊ณ  ์ผ๋ถ€๋Ÿฌ ์•ˆ ์“ด๋‹คโ€๋Š” ์˜๋„๊ฐ€ ์ฝ”๋“œ์— ๋‚จ๋Š”๋‹ค. ์•„๋ฌด ํ‘œ์‹œ ์—†์ด ํ˜๋ ค๋ณด๋‚ด๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฅด๋‹ค.


3. ์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜(sentinel error)

๋•Œ๋กœ๋Š” ํ˜ธ์ถœ์ž๊ฐ€ ์—๋Ÿฌ์˜ ์ข…๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. โ€œ์ฐพ๋Š” ๊ฒŒ ์—†์–ด์„œ ์‹คํŒจโ€์™€ โ€œ๊ถŒํ•œ์ด ์—†์–ด์„œ ์‹คํŒจโ€๋Š” ๋Œ€์‘์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿด ๋•Œ ์“ฐ๋Š” ๊ฒŒ ์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜, ๋ฏธ๋ฆฌ ์ •์˜ํ•ด๋‘” ๋Œ€ํ‘œ ์—๋Ÿฌ ๊ฐ’์ด๋‹ค.

var ErrNotFound = errors.New("not found")
 
func lookup(id int) (string, error) {
    name, ok := db[id]
    if !ok {
        return "", ErrNotFound   // ๋ฏธ๋ฆฌ ์ •์˜ํ•œ ๊ทธ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
    }
    return name, nil
}

ErrNotFound๋Š” ํŒจํ‚ค์ง€ ๋ ˆ๋ฒจ์— ํ•œ ๋ฒˆ ์„ ์–ธํ•ด๋‘๊ณ  ๊ณ„์† ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฆ„ ์•ž์— Err์„ ๋ถ™์ด๋Š” ๊ฒŒ ๊ด€๋ก€๋‹ค(ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ io.EOF, sql.ErrNoRows๊ฐ€ ์ด๋Ÿฐ ์‹์ด๋‹ค).

์„ผํ‹ฐ๋„ฌ์€ "ํƒ€์ž…"์ด ์•„๋‹ˆ๋ผ "๊ฐ’"์ด๋‹ค

์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜๋Š” ์ƒˆ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค. errors.New๋กœ ๋งŒ๋“  ํ‰๋ฒ”ํ•œ ์—๋Ÿฌ ๊ฐ’ ํ•˜๋‚˜๋ฅผ ํŒจํ‚ค์ง€์— ๋ฐ•์•„๋‘๊ณ , ๊ทธ ๊ฐ’ ์ž์ฒด๋ฅผ ์ข…๋ฅ˜์˜ ํ‘œ์‹์œผ๋กœ ์“ฐ๋Š” ๊ฒƒ๋ฟ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ด๊ธฐ๋Š” ์ •๋ณด๋Š” โ€œ์ด ์ข…๋ฅ˜๊ฐ€ ์ผ์–ด๋‚ฌ๋‹คโ€๊ฐ€ ์ „๋ถ€๋‹ค. โ€œ์–ด๋–ค ํ‚ค๋ฅผ ๋ชป ์ฐพ์•˜๋Š”์ง€โ€ ๊ฐ™์€ ๋ถ€๊ฐ€ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋“ค๊ณ  ๊ฐ€์•ผ ํ•œ๋‹ค๋ฉด ๊ฐ’ ํ•˜๋‚˜๋กœ๋Š” ๋ถ€์กฑํ•˜๊ณ , ๊ทธ๋•Œ๋Š” 4ยท5๋ฒˆ์—์„œ ๋‹ค๋ฃฐ ์ปค์Šคํ…€ ์—๋Ÿฌ ํƒ€์ž…(errors.As๋กœ ๊บผ๋‚ด ์“ฐ๋Š”)์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค.

ํ˜ธ์ถœ์ž๋Š” ์ด ๊ฐ’๊ณผ ๋น„๊ตํ•ด์„œ โ€œ์ฐพ๋Š” ๊ฒŒ ์—†๋Š” ๊ฒฝ์šฐโ€๋งŒ ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

name, err := lookup(42)
if errors.Is(err, ErrNotFound) {
    fmt.Println("๊ทธ๋Ÿฐ ID ์—†์Œ, ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ")
    name = "guest"
} else if err != nil {
    return err   // ๋‹ค๋ฅธ ์—๋Ÿฌ๋Š” ์œ„๋กœ ์ „ํŒŒ
}

๋ฌธ์ž์—ด ๋น„๊ต๋Š” ๊ธˆ์ง€

์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ทœ์น™ ํ•˜๋‚˜. ์—๋Ÿฌ๋ฅผ ๋ฉ”์‹œ์ง€ ๋ฌธ์ž์—ด๋กœ ๋น„๊ตํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

// ํ•˜์ง€ ๋ง ๊ฒƒ โ€” ๋ฉ”์‹œ์ง€๊ฐ€ ์กฐ๊ธˆ๋งŒ ๋ฐ”๋€Œ์–ด๋„ ๊นจ์ง„๋‹ค
if err.Error() == "not found" {
    // ...
}

๋ฉ”์‹œ์ง€๋Š” ์‚ฌ๋žŒ์ด ์ฝ์œผ๋ผ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด์ง€ ํ”„๋กœ๊ทธ๋žจ์ด ๋ถ„๊ธฐํ•˜๋ผ๊ณ  ์žˆ๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค. ์˜คํƒ€๋ฅผ ๊ณ ์น˜๊ฑฐ๋‚˜ ๋ฌธ๊ตฌ๋ฅผ ๋‹ค๋“ฌ๋Š” ์ˆœ๊ฐ„ ๋น„๊ต๊ฐ€ ๊นจ์ง„๋‹ค. ๋Œ€์‹  errors.Is(err, ErrNotFound)๋กœ ๊ฐ’ ์ž์ฒด๋ฅผ ๋น„๊ตํ•œ๋‹ค(๋‹ค์Œ ์„น์…˜์—์„œ errors.Is๋ฅผ ์ž์„ธํžˆ ๋ณธ๋‹ค).

๋ชจ๋“  ์—๋Ÿฌ๋ฅผ ์„ผํ‹ฐ๋„ฌ๋กœ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†๋‹ค

์„ผํ‹ฐ๋„ฌ์€ ํ˜ธ์ถœ์ž๊ฐ€ ๊ทธ ์ข…๋ฅ˜๋ฅผ ๋ณด๊ณ  ๋ถ„๊ธฐํ•ด์•ผ ํ•  ๋•Œ๋งŒ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ƒฅ ์œ„๋กœ ์ „ํŒŒํ•˜๋‹ค ๋กœ๊ทธ๋งŒ ๋‚จ๊ธธ ์—๋Ÿฌ๋ผ๋ฉด fmt.Errorf๋กœ ๋งŒ๋“  ์ผ๋ฐ˜ ์—๋Ÿฌ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค. ์„ผํ‹ฐ๋„ฌ์„ ๋‚จ๋ฐœํ•˜๋ฉด ํŒจํ‚ค์ง€์˜ ๊ณต๊ฐœ API๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ , ํ˜ธ์ถœ์ž๊ฐ€ ๊ทธ ๊ฐ’์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ๋‚˜์ค‘์— ๋ฐ”๊พธ๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค.

Python์˜ ์˜ˆ์™ธ ํด๋ž˜์Šค์™€ ๋น„๊ต

Python์—์„œ ์—๋Ÿฌ ์ข…๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฑด ์˜ˆ์™ธ ํด๋ž˜์Šค๋‹ค. except FileNotFoundError์ฒ˜๋Ÿผ ํƒ€์ž…์œผ๋กœ ์žก๋Š”๋‹ค. Go์˜ ์„ผํ‹ฐ๋„ฌ์€ ๊ทธ ์ž๋ฆฌ๋ฅผ ๊ฐ’ ํ•˜๋‚˜๋กœ ๋Œ€์‹ ํ•˜๋Š” ์…ˆ์ด๋ผ, โ€œ์˜ˆ์™ธ ํด๋ž˜์Šค ์—†์ด ๊ฐ’์œผ๋กœ ๋ถ„๊ธฐํ•œ๋‹คโ€๊ฐ€ Python ๊ฐœ๋ฐœ์ž์—๊ฒ ๋‚ฏ์„ค๊ฒŒ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ๋‹ค.


4. ์˜ค๋ฅ˜ ๋ž˜ํ•‘(wrapping)

์—๋Ÿฌ๊ฐ€ ๊นŠ์€ ๊ณณ์—์„œ ์˜ฌ๋ผ์˜ฌ ๋•Œ, ๊ทธ๋ƒฅ ๊ทธ๋Œ€๋กœ ์ „ํŒŒํ•˜๋ฉด โ€œ์–ด๋””์„œ ๋ฌด์—‡์„ ํ•˜๋‹ค ๋‚ฌ๋Š”์ง€โ€ ๋ฌธ๋งฅ์ด ์‚ฌ๋ผ์ง„๋‹ค. not found๋ผ๋Š” ๋ฉ”์‹œ์ง€๋งŒ ๋ด์„œ๋Š” ์–ด๋А ๋‹จ๊ณ„์—์„œ ๋‚ฌ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. ๋ž˜ํ•‘์€ ์›๋ณธ ์—๋Ÿฌ๋ฅผ ๋ณด์กดํ•œ ์ฑ„ ๋ฌธ๋งฅ์„ ๋ง๋ถ™์ด๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

ํ•ต์‹ฌ์€ fmt.Errorf์˜ %w ๋™์‚ฌ๋‹ค.

func fileChecker(name string) error {
    f, err := os.Open(name)
    if err != nil {
        return fmt.Errorf("in fileChecker: %w", err)   // %w๋กœ ์›๋ณธ์„ ๊ฐ์Œˆ
    }
    defer f.Close()
    return nil
}

%w๋กœ ๊ฐ์‹ธ๋ฉด ์ƒˆ ์—๋Ÿฌ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋˜, ๊ทธ ์•ˆ์— ์›๋ณธ ์—๋Ÿฌ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋“ค์–ด ์žˆ๋‹ค. ๋ฉ”์‹œ์ง€๋Š” in fileChecker: open data.txt: no such file or directory์ฒ˜๋Ÿผ ๋ฐ”๊นฅ ๋ฌธ๋งฅ๊ณผ ์›๋ณธ์ด ์ด์–ด์ง„ ํ˜•ํƒœ๊ฐ€ ๋œ๋‹ค. ํ˜ธ์ถœ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ž˜ํ•‘ํ•˜๋ฉด โ€œ์–ด๋”” โ†’ ์–ด๋”” โ†’ ์–ด๋””์„œ ๋‚ฌ๋‹คโ€๋Š” ํ๋ฆ„์ด ํ•œ ์ค„์— ์Œ“์ธ๋‹ค.

%w์™€ %v์˜ ์ฐจ์ด

fmt.Errorf์—์„œ ์—๋Ÿฌ๋ฅผ ๋ผ์šธ ๋•Œ %w์™€ %v๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅด๋‹ค.

  • %v โ€” ์›๋ณธ์˜ ๋ฉ”์‹œ์ง€ ํ…์ŠคํŠธ๋งŒ ๊ฐ€์ ธ๋‹ค ๋ถ™์ธ๋‹ค. ์›๋ณธ ์—๋Ÿฌ ๊ฐ’์€ ๋ฒ„๋ ค์ง„๋‹ค.
  • %w โ€” ์›๋ณธ ์—๋Ÿฌ ๊ฐ’์„ ์ฒด์ธ์— ๋ณด์กดํ•œ๋‹ค. ๋‚˜์ค‘์— errors.Is/errors.As๋กœ ๊บผ๋‚ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ข…๋ฅ˜๋ฅผ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•  ์—๋Ÿฌ๋ผ๋ฉด %w๋กœ ๊ฐ์‹ธ ์ฒด์ธ์„ ์œ ์ง€ํ•˜๊ณ , ๋‹จ์ˆœํžˆ ๋ฉ”์‹œ์ง€๋งŒ ๋‚จ๊ธฐ๋ฉด ๋˜๋Š” ๊ฒฝ์šฐ์—” %v๋ฅผ ์“ด๋‹ค.

errors.Unwrap โ€” ํ•œ ๊ฒน ๋ฒ—๊ธฐ๊ธฐ

๋ž˜ํ•‘๋œ ์—๋Ÿฌ์—์„œ ๋ฐ”๋กœ ์•ˆ์ชฝ ์—๋Ÿฌ๋ฅผ ๊บผ๋‚ด๋Š” ํ•จ์ˆ˜๊ฐ€ errors.Unwrap์ด๋‹ค. ํ•œ ๋ฒˆ์— ํ•œ ๊ฒน์”ฉ ๋ฒ—๊ธด๋‹ค.

err := fileChecker("missing.txt")
inner := errors.Unwrap(err)   // "in fileChecker:" ๋ฅผ ๋ฒ—๊ธฐ๊ณ  ์•ˆ์ชฝ ์—๋Ÿฌ๋ฅผ ๊บผ๋ƒ„

๋‹ค๋งŒ ์‹ค๋ฌด์—์„œ Unwrap์„ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ผ์€ ๋งŽ์ง€ ์•Š๋‹ค. ๋ณดํ†ต์€ ๋‹ค์Œ ์„น์…˜์˜ errors.Is/errors.As๊ฐ€ ๋‚ด๋ถ€์—์„œ ์•Œ์•„์„œ ์ฒด์ธ์„ ๋๊นŒ์ง€ ํ’€๋ฉฐ ๊ฒ€์‚ฌํ•ด์ค€๋‹ค.

์ปค์Šคํ…€ ์—๋Ÿฌ ํƒ€์ž…์„ ์ฒด์ธ์— ์ฐธ์—ฌ์‹œํ‚ค๊ธฐ

๋‚ด๊ฐ€ ๋งŒ๋“  ์—๋Ÿฌ ํƒ€์ž…๋„ Unwrap() error ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋ž˜ํ•‘ ์ฒด์ธ์— ๋‚„ ์ˆ˜ ์žˆ๋‹ค. ์•ˆ์— ๊ฐ์‹ผ ์—๋Ÿฌ๋ฅผ ๋Œ๋ ค์ฃผ๋„๋ก ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

type StatusError struct {
    Code int
    Err  error   // ๊ฐ์‹ผ ์›๋ณธ ์—๋Ÿฌ
}
 
func (e StatusError) Error() string {
    return fmt.Sprintf("status %d: %v", e.Code, e.Err)
}
 
func (e StatusError) Unwrap() error {
    return e.Err   // ์ฒด์ธ์˜ ๋‹ค์Œ ๊ณ ๋ฆฌ๋ฅผ ์•Œ๋ ค์คŒ
}

์ด๋ ‡๊ฒŒ ํ•ด๋‘๋ฉด StatusError๋กœ ๊ฐ์‹ผ ์—๋Ÿฌ๋„ errors.Is/errors.As๊ฐ€ ์•ˆ์ชฝ๊นŒ์ง€ ๋”ฐ๋ผ ๋“ค์–ด๊ฐ€ ๊ฒ€์‚ฌํ•œ๋‹ค.

์–ธ์ œ ๋ž˜ํ•‘ํ•˜๋‚˜

์—๋Ÿฌ๋ฅผ ์œ„๋กœ ๊ทธ๋ƒฅ ํ˜๋ ค๋ณด๋‚ผ ๊ฑฐ๋ฉด ๋ž˜ํ•‘ ์—†์ด ๊ทธ๋Œ€๋กœ return errํ•ด๋„ ๋œ๋‹ค. ๋ž˜ํ•‘์€ ํ˜ธ์ถœ ๊ฒฝ๋กœ์˜ ๋ฌธ๋งฅ์ด ๋””๋ฒ„๊น…์— ๋„์›€์ด ๋  ๋•Œ ํ•œ๋‹ค. โ€œ์–ด๋А ํ•จ์ˆ˜์—์„œ ์ด ์—๋Ÿฌ๋ฅผ ๋ฐ›์•˜๋Š”๊ฐ€โ€๊ฐ€ ์ถ”์ ์— ์˜๋ฏธ ์žˆ๋Š” ์ง€์ ์—์„œ๋งŒ %w๋กœ ํ•œ ๊ฒน ๋ง๋ถ™์ด๋Š” ๊ฒŒ ์ ๋‹นํ•˜๋‹ค. ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ ๋ฌด์ž‘์ • ๊ฐ์‹ธ๋ฉด ๋ฉ”์‹œ์ง€๋งŒ ๊ธธ์–ด์ง„๋‹ค.


5. errors.Is ์™€ errors.As

๋ž˜ํ•‘์ด ์ƒ๊ธฐ๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•˜๋‚˜ ๋”ฐ๋ผ์˜จ๋‹ค. ์—๋Ÿฌ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฒน์œผ๋กœ ๊ฐ์‹ธ์ง€๋ฉด, ๋ฐ”๊นฅ๋งŒ ๋ด์„œ๋Š” ์•ˆ์ชฝ์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค. ๊ทธ๋ž˜์„œ == ์ง์ ‘ ๋น„๊ต๋‚˜ ํƒ€์ž… ๋‹จ์–ธ(type assertion)์ด ๊ฒ‰๋งŒ ๋ณด๊ณ  ์‹คํŒจํ•œ๋‹ค.

err := fileChecker("missing.txt")   // os.ErrNotExist๋ฅผ in fileChecker๋กœ ๊ฐ์Œˆ
 
if err == os.ErrNotExist {          // false โ€” ๋ฐ”๊นฅ์€ fmt๊ฐ€ ๋งŒ๋“  ๋‹ค๋ฅธ ๊ฐ’์ด๋‹ค
    // ์—ฌ๊ธฐ ์ ˆ๋Œ€ ์•ˆ ๋“ค์–ด์˜ด
}

์ด ๋ฌธ์ œ๋ฅผ ํ’€์–ด์ฃผ๋Š” ๊ฒŒ errors.Is์™€ errors.As๋‹ค. ๋‘˜ ๋‹ค ์ฒด์ธ์„ ๋๊นŒ์ง€ ๋”ฐ๋ผ ๋“ค์–ด๊ฐ€๋ฉฐ ๊ฒ€์‚ฌํ•œ๋‹ค.

errors.Is โ€” โ€œ์ด๊ฒŒ ๋ฐ”๋กœ ๊ทธ ์—๋Ÿฌ์•ผ?โ€ (๊ฐ’ ๋น„๊ต)

errors.Is(err, target)๋Š” ์ฒด์ธ ์–ด๋”˜๊ฐ€์— target๊ณผ ๊ฐ™์€ ๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์ฃผ๋กœ ์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜๋ฅผ ์ฐพ์„ ๋•Œ ์“ด๋‹ค.

err := fileChecker("missing.txt")
 
if errors.Is(err, os.ErrNotExist) {   // ์ฒด์ธ์„ ํ’€๋ฉฐ os.ErrNotExist๋ฅผ ์ฐพ์Œ โ†’ true
    fmt.Println("ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค")
}

๊ฒ‰์ด ๋ช‡ ๊ฒน์œผ๋กœ ๊ฐ์‹ธ์˜€๋“ , ์•ˆ์— ๊ทธ ์„ผํ‹ฐ๋„ฌ ๊ฐ’์ด ๋“ค์–ด ์žˆ์œผ๋ฉด true๋‹ค. 3๋ฒˆ์—์„œ โ€œ๋ฌธ์ž์—ด ๋น„๊ต ๊ธˆ์ง€, errors.Is๋กœ ๋น„๊ตโ€๋ผ๊ณ  ํ•œ ๊ฒŒ ์ด๊ฒƒ์ด๋‹ค.

errors.As โ€” โ€œ์ด๋Ÿฐ ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ์žˆ์–ด? ์žˆ์œผ๋ฉด ๊บผ๋‚ด์ค˜โ€ (ํƒ€์ž… ํ™•์ธ + ์ถ”์ถœ)

errors.As(err, &target)๋Š” ์ฒด์ธ ์•ˆ์— ํŠน์ • ํƒ€์ž…์˜ ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์žˆ์œผ๋ฉด ๊ทธ ๊ฐ’์„ target์— ๊บผ๋‚ด ๋‹ด๋Š”๋‹ค. ๊ฐ’ ํ•˜๋‚˜๋ฅผ ์ฝ• ์ง‘์–ด ์ฐพ๋Š” Is์™€ ๋‹ฌ๋ฆฌ, โ€œ์ด ๋ถ€๋ฅ˜์˜ ์—๋Ÿฌโ€๋ฅผ ์ฐพ์•„ ๊ทธ ์•ˆ์˜ ํ•„๋“œ๊นŒ์ง€ ๊บผ๋‚ด ์“ธ ๋•Œ ์“ด๋‹ค.

var statusErr StatusError
if errors.As(err, &statusErr) {        // ์ฒด์ธ์—์„œ StatusError๋ฅผ ์ฐพ์œผ๋ฉด
    fmt.Println("์ƒํƒœ ์ฝ”๋“œ:", statusErr.Code)   // ๊บผ๋‚ธ ๊ฐ’์˜ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉ
}

As์—๋Š” ๋ฐ›์„ ๋ณ€์ˆ˜์˜ ์ฃผ์†Œ(&statusErr)๋ฅผ ๋„˜๊ธด๋‹ค. ์ฐพ์€ ์—๋Ÿฌ๋ฅผ ๊ฑฐ๊ธฐ์— ์ฑ„์›Œ ๋„ฃ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฐ˜ํ™˜๊ฐ’์€ ์ฐพ์•˜๋Š”์ง€ ์—ฌ๋ถ€(bool)๋‹ค.

๋‘˜์„ ๋‚˜๋ž€ํžˆ ์ •๋ฆฌํ•˜๋ฉด

๋ฌด์—‡์„ ๋ฌป๋‚˜๋ฌด์—‡์„ ๋„˜๊ธฐ๋‚˜์–ธ์ œ ์“ฐ๋‚˜
errors.Is(err, target)โ€์ด ๊ฐ’์ด ์ฒด์ธ์— ์žˆ๋‚˜?โ€๋น„๊ตํ•  ์—๋Ÿฌ ๊ฐ’์„ผํ‹ฐ๋„ฌ ์˜ค๋ฅ˜ ๊ตฌ๋ถ„
errors.As(err, &target)โ€์ด ํƒ€์ž…์ด ์ฒด์ธ์— ์žˆ๋‚˜? ๊บผ๋‚ด์ค˜โ€๋‹ด์„ ๋ณ€์ˆ˜์˜ ์ฃผ์†Œ์ปค์Šคํ…€ ์—๋Ÿฌ์˜ ํ•„๋“œ ์‚ฌ์šฉ

comma-ok์ฒ˜๋Ÿผ ์•ˆ์ „ํ•˜๋‹ค

errors.As๋Š” 03ํŽธ์˜ ๋งต ์กฐํšŒ(v, ok := m[k])๋‚˜ ํƒ€์ž… ๋‹จ์–ธ์˜ comma-ok ํ˜•ํƒœ์™€ ๋‹ฎ์•˜๋‹ค. ์ฐพ์œผ๋ฉด ๊ฐ’์„ ์ฑ„์šฐ๊ณ  true, ๋ชป ์ฐพ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋‘๊ณ  false๋ฅผ ์ค€๋‹ค. ํŒจ๋‹‰ ์—†์ด โ€œ์žˆ์œผ๋ฉด ์“ฐ๊ณ , ์—†์œผ๋ฉด ๋ถ„๊ธฐโ€๊ฐ€ ๊น”๋”ํ•˜๊ฒŒ ๋œ๋‹ค. ๋ž˜ํ•‘๋œ ์—๋Ÿฌ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ๋Š” ์ง์ ‘ ==๋‚˜ ๋‹จ์–ธ์„ ์“ฐ์ง€ ๋ง๊ณ  ๊ฑฐ์˜ ํ•ญ์ƒ Is/As๋ฅผ ์“ด๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.


6. panic๊ณผ recover

์ง€๊ธˆ๊นŒ์ง€ ๋ณธ ์—๋Ÿฌ๋Š” ์ „๋ถ€ โ€œ๊ฐ’โ€์ด์—ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ , ํ˜ธ์ถœ์ž๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ณ„์† ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ์œ„ํ—˜ํ•œ ์ƒํ™ฉ์ด ๋”ฐ๋กœ ์žˆ๋‹ค. ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ๋ฅผ ๋” ์ด์ƒ ๋ฏฟ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๋‹ค. ์ด๋Ÿด ๋•Œ ์“ฐ๋Š” ๊ฒŒ panic์ด๋‹ค.

func mustParseConfig(path string) Config {
    data, err := os.ReadFile(path)
    if err != nil {
        panic("ํ•„์ˆ˜ ์„ค์ • ํŒŒ์ผ์„ ์ฝ์„ ์ˆ˜ ์—†์Œ: " + err.Error())
    }
    // ...
}

panic์ด ๋ฐœ์ƒํ•˜๋ฉด ๋ณดํ†ต์˜ ์—๋Ÿฌ์™€ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.

  • ํ˜„์žฌ ํ•จ์ˆ˜์˜ ์‹คํ–‰์ด ์ฆ‰์‹œ ๋ฉˆ์ถ˜๋‹ค
  • ์Œ“์—ฌ ์žˆ๋˜ defer๋“ค์€ ๊ทธ๋ž˜๋„ ์‹คํ–‰๋œ๋‹ค(์ž์› ์ •๋ฆฌ๋Š” ๋ณด์žฅ๋œ๋‹ค)
  • ๊ทธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ์œ„๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ๊ฐ™์€ ์ผ์„ ๋ฐ˜๋ณตํ•œ๋‹ค
  • ๋๊นŒ์ง€ ์•„๋ฌด๋„ ๋ง‰์ง€ ๋ชปํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜๊ณ  ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค

recover โ€” defer ์•ˆ์—์„œ panic์„ ์ˆ˜์Šต

recover๋Š” ์ง„ํ–‰ ์ค‘์ธ panic์„ ๋ฉˆ์ถ”๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ์ •์ƒ ํ๋ฆ„์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค. ๋‹จ, defer๋กœ ๋ฏธ๋ฃฌ ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ ์ž‘๋™ํ•œ๋‹ค(05ํŽธ์˜ defer์™€ ์ด์–ด์ง„๋‹ค). panic์ด defer๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ์„ฑ์งˆ์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

func safeRun() (err error) {
    defer func() {
        if r := recover(); r != nil {       // panic์„ ์žก์•„๋ƒ„
            err = fmt.Errorf("ํŒจ๋‹‰ ๋ณต๊ตฌ: %v", r)   // ์—๋Ÿฌ๋กœ ๋ณ€ํ™˜ํ•ด ๋ฐ˜ํ™˜
        }
    }()
 
    riskyOperation()   // ์—ฌ๊ธฐ์„œ panic์ด ๋‚˜๋„
    return nil         // recover๊ฐ€ ์žก์•„์„œ ์ •์ƒ ๋ฐ˜ํ™˜์œผ๋กœ ๋ฐ”๊ฟˆ
}

์—ฌ๊ธฐ์„œ 05ํŽธ์˜ ๋ช…๋ช…๋œ ๋ฐ˜ํ™˜๊ฐ’(named return value)์ด ํ•จ๊ป˜ ์“ฐ์ธ๋‹ค. recover๋กœ ์žก์€ ๊ฐ’์„ err์— ๋‹ด์œผ๋ฉด, defer๊ฐ€ ๋๋‚œ ๋’ค ๊ทธ err์ด ์ตœ์ข… ๋ฐ˜ํ™˜๊ฐ’์ด ๋œ๋‹ค. panic์„ ์ผ๋ฐ˜ ์—๋Ÿฌ๋กœ ๋ฐ”๊ฟ” ํ˜ธ์ถœ์ž์—๊ฒŒ ์ •์ƒ์ ์œผ๋กœ ๋Œ๋ ค์ฃผ๋Š” ํŒจํ„ด์ด๋‹ค.

๊ธฐ์ค€: error๋ƒ panic์ด๋ƒ

๋‘˜์„ ๊ฐ€๋ฅด๋Š” ๊ธฐ์ค€์€ ๋ช…ํ™•ํ•˜๋‹ค.

errorpanic
์–ด๋–ค ์ƒํ™ฉํ˜ธ์ถœ์ž๊ฐ€ ์ •์ƒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ œ๊ณ„์† ์‹คํ–‰ํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ๋ฅผ ๋ฏฟ์„ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ
์˜ˆ์‹œํŒŒ์ผ ์—†์Œ, ์ž˜๋ชป๋œ ์ž…๋ ฅ, ๋„คํŠธ์›Œํฌ ์‹คํŒจํ”„๋กœ๊ทธ๋ž˜๋จธ ๋ฒ„๊ทธ, ๋ถˆ๋ณ€์‹(invariant) ์œ„๋ฐ˜, ์ดˆ๊ธฐํ™” ์‹คํŒจ, ๋„๋‹ฌ ๋ถˆ๊ฐ€ ๊ฒฝ๋กœ
ํ๋ฆ„์ž๋™ ์ •์ง€ ์—†์Œ, ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์•Œ๋ฆผ์‹คํ–‰ ๊ฐ•์ œ ์ค‘๋‹จ, ์œ„๋กœ ์ „ํŒŒ
๋ง‰์ง€ ์•Š์œผ๋ฉด๊ทธ๋ƒฅ ๋ฌด์‹œ๋จํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ + ์Šคํƒ ํŠธ๋ ˆ์ด์Šค

์‹ค๋ฌด ๊ธฐ์ค€์€ ๋‹จ์ˆœํ•˜๋‹ค. ํ˜ธ์ถœ์ž๊ฐ€ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋ฉด error, ๊ทธ๋ ‡์ง€ ์•Š๊ณ  โ€œ์—ฌ๊ธฐ๊นŒ์ง€ ์™”๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋ฒ„๊ทธโ€์ธ ๋ฌธ์ œ๋ฉด panic. ๋Œ€๋ถ€๋ถ„์˜ ์ผ์ƒ์ ์ธ ์‹คํŒจ๋Š” error๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , panic์€ ์ •๋ง ์˜ˆ์™ธ์ ์ธ ์ƒํ™ฉ์—๋งŒ ๋‚จ๊ฒจ๋‘”๋‹ค.

Python ์˜ˆ์™ธ์™€์˜ ๊ฒฐ์ •์  ์ฐจ์ด

Python์—์„œ ์˜ˆ์™ธ๋Š” ์ผ์ƒ์ ์ธ ํ๋ฆ„ ์ œ์–ด์—๋„ ์“ฐ์ธ๋‹ค. ๋ฐ˜๋ณต์ž๊ฐ€ ๋๋‚˜๋ฉด StopIteration์„ ๋˜์ง€๊ณ , ํ‚ค๊ฐ€ ์—†์œผ๋ฉด KeyError๋ฅผ ๋˜์ง„๋‹ค. try/except๋กœ ํ๋ฆ„์„ ๋ถ„๊ธฐํ•˜๋Š” ๊ฒŒ ํ”ํ•œ ํŒจํ„ด์ด๋‹ค.

Go์˜ panic์€ ๊ทธ ๋ฐ˜๋Œ€๋‹ค. panic์€ ๋น„์ƒ์šฉ์ด๋‹ค. โ€œํ๋ฆ„ ์ œ์–ดโ€๋กœ ์“ฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ •๋ง ๋” ์ง„ํ–‰ํ•˜๋ฉด ์•ˆ ๋  ๋•Œ๋งŒ ํ„ฐ๋œจ๋ฆฐ๋‹ค. Python์˜ ์˜ˆ์™ธ์— ์ต์ˆ™ํ•˜๋‹ค๋ฉด panic์„ try/except์ฒ˜๋Ÿผ ์“ฐ๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, Go์—์„œ ๊ทธ๊ฑด ์•ˆํ‹ฐํŒจํ„ด์ด๋‹ค. Python์˜ ์˜ˆ์™ธ โ‰ˆ Go์˜ error์ด๊ณ , Go์˜ panic์€ Python์—์„œ ์žก์ง€ ์•Š๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ์ฃฝ๊ฒŒ ๋‘๋Š” ์น˜๋ช…์  ์˜ˆ์™ธ์— ๊ฐ€๊น๋‹ค.

panic์„ ํ๋ฆ„ ์ œ์–ด๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ

โ€œ์—๋Ÿฌ ๋ฐ˜ํ™˜์ด ๊ท€์ฐฎ์œผ๋‹ˆ panic์œผ๋กœ ๋˜์ง€๊ณ  recover๋กœ ๋ฐ›์žโ€๋Š” ์œ ํ˜น์ด ์žˆ๋‹ค. Go์—์„œ๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. panic/recover๋Š” ํŒจํ‚ค์ง€ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๊ฒŒ ๊ฐ€๋‘๊ณ , ๊ณต๊ฐœ ํ•จ์ˆ˜๋Š” ๊ฐ€๋Šฅํ•˜๋ฉด error๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋งŒ๋“ ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์•ˆ์—์„œ panic์„ ์“ฐ๋”๋ผ๋„, ๊ฒฝ๊ณ„์—์„œ recover๋กœ ์žก์•„ error๋กœ ๋ฐ”๊ฟ” ๋‚ด๋ณด๋‚ด๋Š” ๊ฒŒ ๊ด€๋ก€๋‹ค.


7. defer๋กœ ์—๋Ÿฌ ๋ž˜ํ•‘ํ•˜๊ธฐ

ํ•จ์ˆ˜์— return ์ง€์ ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ, ๋ชจ๋“  ์—๋Ÿฌ์— ๋˜‘๊ฐ™์€ ๋ฌธ๋งฅ์„ ๋ถ™์ด๋ ค๋ฉด ๋งค๋ฒˆ fmt.Errorf๋ฅผ ๋ฐ˜๋ณตํ•ด์•ผ ํ•œ๋‹ค. ์ด๊ฑธ ํ•œ ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ํŒจํ„ด์ด ์žˆ๋‹ค. ๋ช…๋ช…๋œ ๋ฐ˜ํ™˜๊ฐ’(named return value) ๊ณผ defer ํด๋กœ์ €๋ฅผ ์กฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

func loadUser(id int) (err error) {   // ๋ฐ˜ํ™˜ ์—๋Ÿฌ์— err๋ผ๋Š” ์ด๋ฆ„์„ ์คŒ
    defer func() {
        if err != nil {
            err = fmt.Errorf("loadUser(%d): %w", id, err)   // ๋‚˜๊ฐ€๋Š” ์—๋Ÿฌ์— ๋ฌธ๋งฅ์„ ํ•œ ๋ฒˆ์— ๋ง๋ถ™์ž„
        }
    }()
 
    if err := validateID(id); err != nil {
        return err   // ์—ฌ๊ธฐ์„œ ๋‚˜๊ฐ€๋„
    }
    if err := fetchFromDB(id); err != nil {
        return err   // ์—ฌ๊ธฐ์„œ ๋‚˜๊ฐ€๋„
    }
    return nil       // nil์ด๋ฉด defer๊ฐ€ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Œ
}

return err์ด ์–ด๋А ์ง€์ ์—์„œ ์ผ์–ด๋‚˜๋“ , defer ํด๋กœ์ €๊ฐ€ ๋งˆ์ง€๋ง‰์— err์„ ํ•œ ๋ฒˆ ๊ฒ€์‚ฌํ•ด ๋ฌธ๋งฅ์„ ์ž…ํžŒ๋‹ค. loadUser(42): ... ์ ‘๋‘์‚ฌ๊ฐ€ ๋ชจ๋“  ์‹คํŒจ ๊ฒฝ๋กœ์— ์ž๋™์œผ๋กœ ๋ถ™๋Š”๋‹ค. 05ํŽธ์—์„œ ๋ณธ โ€œdefer๋กœ ๋ช…๋ช…๋œ ๋ฐ˜ํ™˜๊ฐ’ ์ˆ˜์ •โ€์ด ์—๋Ÿฌ ์ฒ˜๋ฆฌ์—์„œ ์ด๋ ‡๊ฒŒ ํ™œ์šฉ๋œ๋‹ค.

๊ณผํ•˜๋ฉด ๊ฐ€๋…์„ฑ์„ ํ•ด์นœ๋‹ค

์ด ํŒจํ„ด์€ return ์ง€์ ์ด ๋งŽ๊ณ  ๋ฌธ๋งฅ์ด ๊ณตํ†ต์ผ ๋•Œ ์œ ์šฉํ•˜์ง€๋งŒ, ๋‚จ์šฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ์–ด๋””์„œ ์–ด๋–ป๊ฒŒ ๊ฐ€๊ณต๋˜๋Š”์ง€ ํ•œ๋ˆˆ์— ์•ˆ ๋“ค์–ด์˜จ๋‹ค. return์ด ํ•œ๋‘ ๊ฐœ๋ฟ์ด๋ผ๋ฉด ๊ทธ๋ƒฅ ๊ทธ ์ž๋ฆฌ์—์„œ fmt.Errorf("...: %w", err)๋กœ ๊ฐ์‹ธ๋Š” ๊ฒŒ ๋” ์ฝ๊ธฐ ์‰ฝ๋‹ค. defer ๋ž˜ํ•‘์€ โ€œ๊ณตํ†ต ๋ฌธ๋งฅ์„ ํ•œ ๋ฒˆ์— ๋ถ™์ผ ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ๋•Œโ€๋งŒ ์“ด๋‹ค.

Python ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ํ•œ ์ค„ ์š”์•ฝ

Go์—์„œ ์—๋Ÿฌ๋Š” ๋˜์ง€๊ณ  ๋ฐ›๋Š” ์˜ˆ์™ธ๊ฐ€ ์•„๋‹ˆ๋ผ, ๋ฐ˜ํ™˜ํ•˜๊ณ  ํ™•์ธํ•˜๋Š” ๊ฐ’์ด๋‹ค. if err != nil์ด ๋ฐ˜๋ณต๋ผ๋„, ์‹คํŒจ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ง€์ ์ด ์ฝ”๋“œ์— ๋“œ๋Ÿฌ๋‚œ๋‹ค๋Š” ๊ฒŒ ์ด ๋ฐฉ์‹์˜ ํ•ต์‹ฌ์ด๋‹ค. panic์€ ๊ทธ ๊ทœ์น™์˜ ์˜ˆ์™ธ๊ฐ€ ์•„๋‹ˆ๋ผ, ๊ทœ์น™์ด ํ†ตํ•˜์ง€ ์•Š๋Š” ๋น„์ƒ ์ƒํ™ฉ ์ „์šฉ์œผ๋กœ๋งŒ ๋‚จ๊ฒจ๋‘”๋‹ค.