
Go 프로그래밍의 시작, 왜 변수와 상수를 제대로 알아야 할까요
Go 언어를 처음 접하고 코드를 작성할 때, 가장 먼저 마주치는 당혹스러운 순간은 아마 컴파일러가 던지는 빨간색 에러 메시지일 거예요. 분명히 변수를 선언했는데 사용하지 않았다고 혼을 내거나, 분명히 값이 있는 것 같은데 타입이 맞지 않는다며 실행조차 허락하지 않는 상황을 자주 겪게 되거든요.
단순히 값을 담는 바구니라고 생각했던 변수가 Go에서는 생각보다 훨씬 엄격하고 정교하게 작동해요. 특히 Go 변수 완벽 가이드를 찾는 분들이라면, 단순히 문법을 외우는 것을 넘어 왜 Go가 이렇게 까다로운 규칙을 적용하는지 이해하는 것이 무엇보다 중요해요. 이 엄격함이야말로 대규모 시스템에서도 버그를 최소화하고 안정적인 소프트웨어를 만드는 Go만의 강력한 무기이기 때문이에요.
변수와 상수의 개념을 대충 훑고 지나가면, 나중에 코드의 규모가 커졌을 때 원인을 알 수 없는 논리 오류나 메모리 낭비 문제로 고생할 수 있어요. 예를 들어, 상수로 관리해야 할 값을 실수로 변수로 선언해 프로그램 중간에 값이 바뀌어버린다면, 시스템 전체의 신뢰도가 무너지는 치명적인 사고로 이어질 수도 있어요.
이 글을 끝까지 읽고 나면 여러분은 다음과 같은 능력을 갖추게 될 거예요.
- Go의 엄격한 타입 시스템을 이해하고 에러를 미리 방지하는 법
- 상황에 맞는 최적의 변수 선언 방식을 선택하는 안목
- iota를 활용해 효율적으로 상수를 관리하는 고급 기술
- 실무에서 흔히 발생하는 변수 관련 실수와 그 해결책
이제 기초부터 실전 노하우까지 차근차근 함께 알아가도록 해요.
실전 코딩 전 반드시 체크해야 할 기본 개념
본격적으로 코드를 작성하기 전에, Go 언어가 데이터를 다루는 기본적인 철학을 이해해야 해요. Go는 다른 언어들에 비해 타입 안정성(Type Safety)을 매우 중요하게 여겨요. 이는 한 번 정해진 변수의 타입은 함부로 바꿀 수 없으며, 서로 다른 타입끼리의 연산을 매우 엄격하게 제한한다는 뜻이에요.
개발을 시작하기 전, 여러분이 어떤 도구를 사용하여 변수를 선언할지 결정하는 기준을 세워야 해요. 무턱대고 모든 곳에 단축 선언(Short Variable Declaration)을 남발하다가는 나중에 코드의 가독성이 떨어지거나, 패키지 수준에서 변수를 선언할 수 없는 제약에 부딪혀 당황하게 될 거예요.
아래 표를 통해 변수 선언 방식의 차이점을 명확히 비교해 보세요.
| 선언 방식 | 사용 위치 | 특징 | 권장 상황 |
|---|---|---|---|
| var 키워드 | 함수 내부 및 외부(패키지) | 명시적 타입 지정 가능 | 전역 변수 또는 초기값 없는 변수 |
| : (단축 선언) | 함수 내부만 가능 | 타입 추론 자동 수행 | 함수 내 지역 변수 선언 시 |
| const 키워드 | 함수 내부 및 외부 | 변경 불가능한 값 | 설정값, 수학적 상수 등 |
또한, Go에서는 변수를 선언만 하고 사용하지 않으면 컴파일 단계에서 즉시 에러를 발생시켜요. 이는 불필요한 메모리 사용을 막고 코드를 깔끔하게 유지하려는 Go의 의도예요. 따라서 코드를 짤 때 선언과 동시에 사용 계획을 세우는 습관이 필요해요.
Go의 모든 변수는 선언 시 초기화하지 않으면 각 타입의 Zero Value(제로 값)로 자동 설정돼요. 예를 들어 정수는 0, 불리언은 false, 문자열은 “”가 기본값이 된답니다.
이러한 기본 규칙들을 숙지했다면, 이제 실제 코드에서 어떻게 변수와 상수를 다루는지 구체적인 단계를 통해 살펴볼 준비가 되었어요.
Go 변수와 상수 완벽 활용을 위한 5단계 실행 가이드
이제 이론을 넘어 실제 코드로 어떻게 구현하는지 단계별로 깊이 있게 파헤쳐 볼게요. Go의 변수 관리 방식은 매우 체계적이라, 이 흐름을 이해하면 다른 언어를 배울 때도 큰 도움이 될 거예요.
STEP 1. 상황에 맞는 변수 선언 방식 선택하기
Go에서 변수를 선언하는 방법은 크게 두 가지예요. 첫 번째는 var 키워드를 사용하는 것이고, 두 번째는 : 기호를 사용하는 단축 선언 방식이에요.
패키지 수준(함수 밖)에서 변수를 만들 때는 반드시 var를 사용해야 해요. 단축 선언은 오직 함수 내부에서만 작동하기 때문이에요. 만약 함수 밖에서 :=를 쓰려고 하면 컴파일 에러를 마주하게 될 거예요.
실무에서는 다음과 같은 기준으로 선택해요.
- var 사용: 변수의 타입을 명확하게 보여주고 싶을 때, 혹은 선언만 먼저 하고 나중에 값을 할당해야 할 때 사용해요.
- 단축 선언 사용: 함수 내부에서 지역 변수를 빠르게 만들고, 타입이 명확할 때 코드의 간결함을 위해 사용해요.
단축 선언을 사용할 때는 변수의 타입이 자동으로 결정되므로, 의도치 않은 타입으로 추론되지 않는지 항상 확인해야 해요. 예를 들어 정수를 기대했는데 실수형으로 추론되는 경우 연산 에러가 발생할 수 있어요.
STEP 2. 강력한 타입 시스템과 형 변환 이해하기
Go는 타입에 정말 엄격해요. 예를 들어, int 타입인 변수와 int64 타입인 변수를 더하려고 하면 바로 에러가 발생해요. 다른 언어처럼 자동으로 타입을 맞춰주는 ‘암시적 형 변환’을 허용하지 않기 때문이에요.
이 문제를 해결하려면 반드시 명시적 형 변환(Explicit Conversion)을 수행해야 해요. 코드를 작성할 때 다음과 같은 흐름을 기억하세요.
- 두 변수의 정확한 타입을 확인한다.
- 필요하다면
int64(변수명)처럼 명시적으로 타입을 감싸준다. - 연산을 수행한다.
이런 엄격함 덕분에 개발자는 데이터 손실이나 예기치 못한 계산 오류를 컴파일 단계에서 미리 잡아낼 수 있는 강력한 보호막을 얻게 되는 셈이에요.
STEP 3. iota를 활용한 효율적인 상수 관리 기법
프로그래밍을 하다 보면 상태 값(예: 진행 중, 완료, 대기)이나 요일 같은 값을 정의해야 할 때가 있어요. 이때 const와 iota를 조합하면 매우 깔끔하게 코드를 작성할 수 있어요.
iota는 Go에서 상수를 정의할 때 사용하는 특수 키워드로, 0부터 시작하여 자동으로 1씩 증가하는 값을 생성해 줘요. 매번 숫자를 직접 타이핑할 필요가 없어 실수를 방지하고 유지보수가 매우 쉬워져요.
실제 시나리오를 하나 가정해 볼게요. 주문 시스템의 상태 값을 정의해야 한다면 다음과 같이 작성할 수 있어요.
const (
Pending = iota // 0
Processing // 1
Shipped // 2
Delivered // 3
)
이렇게 작성하면 나중에 새로운 상태인 ‘Cancelled’를 중간에 끼워 넣더라도, 뒤에 오는 값들이 자동으로 조정되어 매우 안전해요. 상수 관리의 마법사라고 불러도 손색이 없겠죠?
STEP 4. 변수 스코프(Scope)와 섀도잉(Shadowing) 주의하기
변수가 어디까지 살아있는지를 결정하는 ‘스코프’ 개념은 Go에서 특히 조심해야 할 부분이에요. 가장 위험한 상황은 바로 변수 섀도잉(Variable Shadowing)이에요. 이는 이미 존재하는 변수와 똑같은 이름의 변수를 더 좁은 범위(예: if문 내부나 함수 내부)에서 다시 선언할 때 발생해요.
겉보기에는 문제가 없어 보이지만, 내부 블록에서 선언된 변수가 외부의 변수를 ‘가려버리기’ 때문에, 값을 변경했다고 생각했는데 실제로는 외부 변수에는 아무런 영향도 주지 못하는 상황이 발생해요. 이는 논리적 버그를 만드는 아주 흔한 원인이에요.
이를 방지하기 위해서는 변수 이름을 지을 때 너무 범용적인 이름(예: err, data 등)을 남발하지 말고, 문맥을 충분히 담을 수 있는 이름을 사용하는 것이 좋아요.
STEP 5. 프로덕션 환경을 위한 명명 규칙과 설계 전략
실제 서비스가 돌아가는 프로덕션 환경에서는 가독성과 유지보수성이 생명이에요. Go 개발자들은 다음과 같은 명명 규칙을 관례적으로 따라요.
- CamelCase 사용: 변수나 함수 이름은 단어의 첫 글자를 대문자로 쓰는 CamelCase를 사용해요.
- 가시성(Visibility) 조절: 이름의 첫 글자를 대문자로 시작하면 외부 패키지에서 접근 가능한 Public 변수가 되고, 소문자로 시작하면 해당 패키지 내부에서만 쓰는 Private 변수가 돼요.
- 매직 넘버 제거: 코드 중간에 갑자기 나타나는 의미를 알 수 없는 숫자(예: 86400)를 그대로 쓰지 마세요. 대신
const SecondsInADay = 86400처럼 상수로 정의해서 사용해야 해요.
이러한 전략들을 적용하면 동료 개발자가 여러분의 코드를 보았을 때, 마치 설명서를 읽는 것처럼 명확하게 의意를 파악할 수 있을 거예요.
자주 하는 실수와 해결법
Go를 배우며 누구나 한 번쯤 겪게 되는 실수들을 정리했어요. 이 패턴들만 익혀두어도 삽질 시간을 대폭 줄일 수 있어요.
- ❌ 사용하지 않는 변수 선언 →
왜 발생하는가: Go는 선언 후 사용되지 않는 변수를 허용하지 않아요.
✅ 해결법: 변수를 즉시 사용하거나, 디버깅 중이라면 언더스코어(“_”)를 사용해 무시하세요. - ❌ 패키지 레벨에서의 단축 선언(:=) 사용 →
왜 발생하는가::=는 함수 내부 전용 문법이에요.
✅ 해결법: 패키지 수준에서는 반드시var키워드를 사용하세요. - ❌ 서로 다른 타입 간의 직접 연산 →
왜 발생하는가: Go는 암시적 형 변환을 지원하지 않아요.
✅ 해결법:int64(a) + b처럼 명시적으로 타입을 맞춰주세요. - ❌ 변수 섀도잉으로 인한 값 누락 →
왜 발생하는가: 동일한 이름의 변수를 내부 블록에서 다시 선언하여 외부 변수를 가려버려요.
✅ 해결법: 변수 이름을 더 구체적으로 짓거나, 중복 선언을 피하세요. - ❌ 상수 자리에 변수 사용 →
왜 발생하는가: 값이 변하면 안 되는 곳에var를 사용해 의도치 않은 변경을 허용하게 돼요.
✅ 해결법: 고정된 값은 반드시const로 선언하세요. - ❌ 제로 값(Zero Value)에 대한 오해 →
왜 발생하는가: 변수가 초기화되지 않았을 때 예상치 못한 기본값이 들어있는 것을 모를 때가 있어요.
✅ 해결법: 변수가 선언될 때 어떤 기본값을 갖는지 항상 인지하고 코드를 설계하세요.
자주 묻는 질문
Q. var와 :=의 차이점을 한 문장으로 요약하면 무엇인가요?
var는 타입 지정과 선언 위치(함수 밖/안)를 자유롭게 선택할 수 있는 범용적인 방식이고, :=는 함수 내부에서 타입을 자동으로 추론하여 빠르게 선언하는 단축 방식이에요.
Q. 상수는 정말로 절대로 바꿀 수 없나요?
네, 맞아요. Go에서 const로 선언된 값은 컴파일 타임에 결정되며, 프로그램 실행 중에 절대 변경할 수 없도록 언어 차원에서 막아두고 있어요.
Q. iota를 사용할 때 0부터 시작하지 않게 하려면 어떻게 하나요?
간단해요! const MyEnum = iota + 1과 같이 식을 더해주면 원하는 시작 숫자부터 값을 부여할 수 있답니다.
Q. 전역 변수를 사용해도 괜찮을까요?
가급적 피하는 것이 좋아요. 전역 변수는 어디서든 수정할 수 있어 코드의 흐름을 추적하기 어렵게 만들거든요. 꼭 필요한 경우가 아니라면 함수 내부의 지역 변수로 관리하는 것을 권장해요.
Q. Go에서 문자열은 변수의 타입인가요?
네, string은 Go의 아주 기본적인 빌트인 타입 중 하나예요. 상수로도 정의할 수 있고 변수로도 선언할 수 있어요.
변수와 상수의 핵심 요약 및 다음 단계
오늘 배운 내용을 잊지 않도록 핵심만 다시 한번 짚어볼게요. 이 체크리스트를 옆에 두고 코딩을 시작해 보세요.
- 변수 선언은 패키지 수준에서는
var, 함수 내부에서는:=를 활용하세요. - 타입이 다르면 반드시 명시적 형 변환을 거쳐야 연산이 가능해요.
- 연속된 상수를 정의할 때는
iota를 써서 코드를 간결하게 만드세요. - 변수 섀도잉은 논리적 버그의 주범이므로 이름 중복을 주의하세요.
- 상수는 변하지 않는 값을, 변수는 변하는 데이터를 담는 용도로 명확히 구분하세요.
- 가시성을 조절하려면 이름의 첫 글자를 대문자 혹은 소문자로 결정하세요.
이제 여러분은 Go의 기초를 튼튼하게 다졌어요. 이론을 아는 것과 직접 타이핑하는 것은 하늘과 땅 차이에요. 오늘 바로 에디터를 켜고 다음 미션을 수행해 보세요!
🚀 오늘 할 일: Go Playground에서 iota를 사용해 요일 상수를 직접 만들어 보세요.
📅 이번 주 할 일: 기존에 작성했던 코드 중 매직 넘버(의미 없는 숫자)를 찾아 상수로 바꾸는 리팩토링을 진행해 보세요.
🛠️ 실행 직전 할 일: 변수 이름을 지을 때, 이 변수가 패키지 밖에서도 쓰일 것인지(대문자 시작) 먼저 결정하는 습관을 들여 보세요.
변수와 상수의 개념을 넘어, 이제 Go의 데이터 구조와 제어문으로 나아갈 준비가 되셨나요? 다음 편에서는 Go의 핵심 중의 핵심인 슬라이스와 맵을 다룰 예정이에요. 더 깊이 있는 Go 개발자로 성장하고 싶다면 구독을 통해 다음 가이드를 놓치지 마세요!
관련하여 더 궁금한 점이 있다면, Go 공식 문서를 참고하거나 커뮤니티에 질문해 보는 것도 아주 좋은 방법이에요.