“값이 없음"을 어떻게 표현할까?

예를 들어 사용자 정보를 담는 구조체가 있으면.

type User struct {
    Name string
    Age  int
}

user := User{Name: "홍길동"}
fmt.Println(user.Age) // 0

여기서 문제가 생긴다. user.Age가 0인데, 이게 진짜 0살인지 아니면 나이 정보가 없는 건지 구분할 수 없다.

해결책 1: 포인터 사용

type User struct {
    Name string
    Age  *int
}

// 나이를 아는 경우
age := 25
user1 := User{Name: "김철수", Age: &age}

// 나이를 모르는 경우
user2 := User{Name: "박영희", Age: nil}

// 사용할 때
if user1.Age != nil {
    fmt.Printf("%s 나이: %d\n", user1.Name, *user1.Age)
} else {
    fmt.Printf("%s 나이 정보 없음\n", user1.Name)
}

이렇게 하면 nil로 “값이 없음"을 명확하게 표현할 수 있다.

해결책 2: bool 플래그 사용

type User struct {
    Name   string
    Age    int
    HasAge bool
}

user1 := User{Name: "김철수", Age: 25, HasAge: true}
user2 := User{Name: "박영희", HasAge: false}

if user1.HasAge {
    fmt.Printf("%s 나이: %d\n", user1.Name, user1.Age)
} else {
    fmt.Printf("%s 나이 정보 없음\n", user1.Name)
}

JSON에서는 포인터가 유용하다

JSON을 다룰 때는 포인터 방식이 더 편리하다.

type User struct {
    Name string `json:"name"`
    Age  *int   `json:"age,omitempty"`
}

// JSON: {"name": "홍길동", "age": 25}
// 파싱하면 Age는 25를 가리키는 포인터

// JSON: {"name": "김철수"}  
// 파싱하면 Age는 nil

omitempty 태그와 포인터를 함께 쓰면, 값이 없을 때 JSON에서 해당 필드를 아예 생략할 수 있다.

주의사항

포인터를 함수 파라미터로 넘길 때 조심해야 함.

func updateAge(user *User, newAge int) {
    if user == nil {
        return // nil이면 아무것도 할 수 없음
    }
    age := newAge
    user.Age = &age
}

nil 포인터를 받으면 값을 설정할 수 없으니까 항상 nil 체크를 해야 함.

결론

  • 일반적인 경우: bool 플래그 방식이 더 안전
  • JSON 처리: 포인터 + nil 방식이 편리
  • 항상 nil 체크 잊지 말기