[2026] Swift 변수와 타입 | var, let, 옵셔널
이 글의 핵심
Swift 변수와 타입: var, let, 옵셔널. 변수와 상수·기본 타입.
들어가며
타입 추론과 옵셔널(?)으로 “값이 없을 수 있음”을 타입에 표시합니다. guard let·if let으로 언랩 흐름을 명확히 두는 패턴이 흔합니다.
실무에서 마주한 현실
개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.
1. 변수와 상수
var vs let
아래 코드는 swift를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 변수 (var): 변경 가능
var name = "홍길동"
name = "김철수" // OK
print(name) // 김철수
// 상수 (let): 변경 불가
let age = 25
// age = 26 // 컴파일 에러!
// 권장: 기본적으로 let 사용, 필요할 때만 var
let maxCount = 100
var currentCount = 0
타입 추론
아래 코드는 swift를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// 타입 추론 (권장)
let name = "홍길동" // String으로 추론
let age = 25 // Int로 추론
let pi = 3.14 // Double로 추론
// 명시적 타입 (필요 시)
let name: String = "홍길동"
let age: Int = 25
let pi: Double = 3.14
2. 기본 타입
정수 타입
다음은 swift를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Int (플랫폼에 따라 32bit 또는 64bit)
let int: Int = 10
let negativeInt: Int = -10
// UInt (부호 없는 정수)
let uint: UInt = 10
// let negativeUInt: UInt = -10 // 에러!
// 크기별 정수
let int8: Int8 = 127
let int16: Int16 = 32767
let int32: Int32 = 2147483647
let int64: Int64 = 9223372036854775807
// 최소/최대값
print(Int.min) // -9223372036854775808
print(Int.max) // 9223372036854775807
실수 타입
아래 코드는 swift를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// Double (64bit, 기본)
let double: Double = 3.14159265359
// Float (32bit)
let float: Float = 3.14
// 타입 명시 필요
let pi = 3.14 // Double로 추론
let piFloat: Float = 3.14 // Float로 명시
문자열
다음은 swift를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
let text: String = "Hello, Swift!"
// 문자열 보간
let name = "홍길동"
let age = 25
let message = "이름: \(name), 나이: \(age)"
print(message)
// 여러 줄 문자열
let multiline = """
첫 번째 줄
두 번째 줄
세 번째 줄
"""
// 문자열 연산
let hello = "Hello"
let world = "World"
let greeting = hello + ", " + world + "!"
불리언
아래 코드는 swift를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
let isActive: Bool = true
let isCompleted: Bool = false
// 논리 연산
let result1 = true && false // false
let result2 = true || false // true
let result3 = !true // false
3. 옵셔널 (Optional)
옵셔널이란?
아래 코드는 swift를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// 일반 변수: nil 불가
var name: String = "홍길동"
// name = nil // 에러!
// 옵셔널: nil 가능
var optionalName: String? = "홍길동"
optionalName = nil // OK
print(optionalName) // Optional("홍길동") 또는 nil
옵셔널 바인딩 (if let)
옵셔널 값을 안전하게 추출하는 방법입니다: 다음은 swift를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
var name: String? = "홍길동"
// if let: 옵셔널 바인딩
if let unwrappedName = name {
// name이 nil이 아니면 이 블록 실행
// unwrappedName: String 타입 (옵셔널 아님)
// name의 값이 unwrappedName에 언래핑되어 할당됨
print("이름: \(unwrappedName)")
// unwrappedName은 이 블록 안에서만 유효
} else {
// name이 nil이면 이 블록 실행
print("이름 없음")
}
// 여러 옵셔널 동시 바인딩
let firstName: String? = "홍"
let lastName: String? = "길동"
if let first = firstName, let last = lastName {
// 둘 다 nil이 아닐 때만 실행
print("이름: \(first)\(last)") // 이름: 홍길동
}
// guard let: 조기 반환 패턴
func greet(name: String?) {
// guard: 조건이 false면 else 블록 실행 후 반환
guard let name = name else {
// name이 nil이면 여기 실행
print("이름 없음")
return // 함수 종료 (guard는 반드시 return/throw/break 필요)
}
// 여기서는 name이 nil이 아님을 보장
// name: String 타입 (언래핑됨)
// guard let으로 추출한 변수는 함수 끝까지 유효
print("안녕하세요, \(name)님!")
// 추가 로직 작성 가능 (들여쓰기 깊이 감소)
}
greet(name: "홍길동") // 안녕하세요, 홍길동님!
greet(name: nil) // 이름 없음
if let vs guard let: 다음은 swift를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// if let: 옵셔널이 있을 때 처리
func processUser(user: User?) {
if let user = user {
// user 처리 (들여쓰기 깊어짐)
print(user.name)
// 여러 줄 로직...
}
}
// guard let: 옵셔널이 없으면 조기 반환 (권장)
func processUser(user: User?) {
guard let user = user else {
return // nil이면 즉시 종료
}
// 정상 흐름 (들여쓰기 얕음)
print(user.name)
// 여러 줄 로직...
}
여러 조건 체크: 아래 코드는 swift를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
func validateUser(name: String?, age: Int?, email: String?) {
// 모든 값이 nil이 아닌지 한 번에 체크
guard let name = name,
let age = age,
let email = email,
age >= 18, // 추가 조건도 가능
email.contains("@") else {
print("유효하지 않은 사용자")
return
}
// 모든 조건을 통과한 경우
print("유효한 사용자: \(name), \(age)세, \(email)")
}
옵셔널 체이닝
아래 코드는 swift를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
struct User {
var name: String
var email: String?
}
let user: User? = User(name: "홍길동", email: "hong@example.com")
// 옵셔널 체이닝
let emailLength = user?.email?.count
print(emailLength) // Optional(17)
// 여러 단계
let firstChar = user?.email?.first?.uppercased()
Nil 병합 연산자 (??)
아래 코드는 swift를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
let name: String? = nil
let displayName = name ?? "Guest"
print(displayName) // Guest
// 체이닝
let email: String? = nil
let backup: String? = nil
let result = email ?? backup ?? "default@example.com"
강제 언래핑 (!)
아래 코드는 swift를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
let name: String? = "홍길동"
// 강제 언래핑 (위험!)
print(name!) // 홍길동
// nil이면 크래시
let nilName: String? = nil
// print(nilName!) // 런타임 에러!
// 암시적 언래핑 옵셔널
var implicitName: String! = "홍길동"
print(implicitName) // 자동 언래핑
4. 타입 변환
아래 코드는 swift를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 정수 → 실수
let intValue: Int = 10
let doubleValue: Double = Double(intValue)
// 문자열 → 정수
let str = "123"
if let number = Int(str) {
print(number) // 123
}
// 실패 시 nil
let invalid = Int("abc") // nil
5. 실전 예제
예제: 사용자 정보 처리
다음은 swift를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
struct User {
let name: String
var age: Int
var email: String?
}
func printUserInfo(user: User?) {
guard let user = user else {
print("사용자 없음")
return
}
print("이름: \(user.name)")
print("나이: \(user.age)")
if let email = user.email {
print("이메일: \(email)")
} else {
print("이메일 미등록")
}
}
let user1 = User(name: "홍길동", age: 25, email: "hong@example.com")
let user2 = User(name: "김철수", age: 30, email: nil)
printUserInfo(user: user1)
printUserInfo(user: user2)
정리
핵심 요약
- var: 변수(변경 가능), let: 상수(변경 불가)
- 기본 타입: Int, Double, String, Bool
- 옵셔널: nil 가능,
?로 표시 - 옵셔널 바인딩: if let, guard let
- 옵셔널 체이닝:
?.로 안전 접근 - Nil 병합:
??로 기본값